@innovastudio/contentbox 1.6.178 → 1.6.180

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.
@@ -8869,6 +8869,7 @@ class Text {
8869
8869
  }
8870
8870
 
8871
8871
  cleanColorClasses(elm) {
8872
+ elm.classList.remove('text-white');
8872
8873
  elm.classList.remove('text-black');
8873
8874
  elm.classList.remove('text-gray-50');
8874
8875
  elm.classList.remove('text-gray-100');
@@ -10753,7 +10754,7 @@ class PanelText {
10753
10754
  <div class="inp-fontfamily" style="width:218px;">
10754
10755
  </div>
10755
10756
 
10756
- <div class="label changedevice">
10757
+ <div class="label changedevice mt-3">
10757
10758
  <span>${out('Font Size')}:</span>
10758
10759
  <span class="val-fontsize" style="flex-grow:1;margin-left:9px"></span>
10759
10760
  <button title="${out('Change Device')}" class="btn-device"><svg style="width:13px;height:13px;"><use xlink:href="#icon-devices"></use></svg></button>
@@ -10766,7 +10767,7 @@ class PanelText {
10766
10767
  <button title="${out('Clear')}" data-value=""><svg><use xlink:href="#icon-eraser"></use></svg></button>
10767
10768
  </div>
10768
10769
 
10769
- <div class="label flex flex-row">
10770
+ <div class="label flex flex-row mt-2">
10770
10771
  <span>${out('Font Weight')}:</span>
10771
10772
  <span class="val-fontweight" style="flex-grow:1;margin-left:9px"></span>
10772
10773
  </div>
@@ -10813,7 +10814,7 @@ class PanelText {
10813
10814
  <button title="${out('Clear')}" data-value=""><svg><use xlink:href="#icon-eraser"></use></svg></button>
10814
10815
  </div>
10815
10816
 
10816
- <div class="label flex flex-row">
10817
+ <div class="label flex flex-row mt-2">
10817
10818
  <span>${out('Letter Spacing')}:</span>
10818
10819
  <span class="val-letterspacing" style="flex-grow:1;margin-left:9px"></span>
10819
10820
  </div>
@@ -10826,7 +10827,7 @@ class PanelText {
10826
10827
  <button title="${out('Clear')}" data-value=""><svg><use xlink:href="#icon-eraser"></use></svg></button>
10827
10828
  </div>
10828
10829
 
10829
- <div class="label">${out('List & Indentation')}:</div>
10830
+ <div class="label mt-2">${out('List & Indentation')}:</div>
10830
10831
 
10831
10832
  <div class="group listindent">
10832
10833
  <button title="${out('Bullets')}" data-action="insertUnorderedList"><svg style="width:12px;height:12px;"><use xlink:href="#icon-list-bullet"></use></svg></button>
@@ -10834,6 +10835,63 @@ class PanelText {
10834
10835
  <button title="${out('Indent')}" data-action="indent"><svg style="width:12px;height:12px;"><use xlink:href="#icon-indent"></use></svg></button>
10835
10836
  <button title="${out('Outdent')}" data-action="outdent"><svg style="width:12px;height:12px;"><use xlink:href="#icon-outdent"></use></svg></use></svg></svg></button>
10836
10837
  </div>
10838
+
10839
+ <div class="label mt-2">${out('Top Spacing')}:</div>
10840
+
10841
+ <div class="group textspacing">
10842
+ <button title="2" data-topspacing="2">2</button>
10843
+ <button title="4" data-topspacing="4">4</button>
10844
+ <button title="6" data-topspacing="6">6</button>
10845
+ <button title="8" data-topspacing="8">8</button>
10846
+ <button title="10" data-topspacing="10">10</button>
10847
+ <button title="12" data-topspacing="12">12</button>
10848
+ <button title="14" data-topspacing="14">14</button>
10849
+ <button title="16" data-topspacing="16">16</button>
10850
+ <button title="20" data-topspacing="20">20</button>
10851
+ <button title="${out('Clear')}" data-topspacing=""><svg><use xlink:href="#icon-eraser"></use></svg></button>
10852
+ </div>
10853
+
10854
+ <div class="label mt-2">${out('Bottom Spacing')}:</div>
10855
+
10856
+ <div class="group textspacing">
10857
+ <button title="2" data-bottomspacing="2">2</button>
10858
+ <button title="4" data-bottomspacing="4">4</button>
10859
+ <button title="6" data-bottomspacing="6">6</button>
10860
+ <button title="8" data-bottomspacing="8">8</button>
10861
+ <button title="10" data-bottomspacing="10">10</button>
10862
+ <button title="12" data-bottomspacing="12">12</button>
10863
+ <button title="14" data-bottomspacing="14">14</button>
10864
+ <button title="16" data-bottomspacing="16">16</button>
10865
+ <button title="20" data-bottomspacing="20">20</button>
10866
+ <button title="${out('Clear')}" data-bottomspacing=""><svg><use xlink:href="#icon-eraser"></use></svg></button>
10867
+ </div>
10868
+
10869
+ <div class="flex items-end mt-1">
10870
+ <label>
10871
+ <div class="mt-2 mb-2">${out('Max Width')} (px):</div>
10872
+ <input type="number" class="inp-maxwidth" style="width:80px" min="0">&nbsp;
10873
+ </label>
10874
+
10875
+ <button class="btn-blockcenter toggle" data-blockalign="left" title="${out('Left')}">
10876
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
10877
+ <rect x="3" y="3" width="18" height="18" rx="2" opacity="0.6"/>
10878
+ <rect x="5" y="7" width="7" height="10" rx="1"/>
10879
+ </svg>
10880
+ </button>
10881
+ <button class="btn-blockcenter toggle" data-blockalign="center" title="${out('Center')}">
10882
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
10883
+ <rect x="3" y="3" width="18" height="18" rx="2" opacity="0.6"/>
10884
+ <rect x="8.5" y="7" width="7" height="10" rx="1"/>
10885
+ </svg>
10886
+ </button>
10887
+ <button class="btn-blockcenter toggle" data-blockalign="right" title="${out('Right')}">
10888
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
10889
+ <rect x="3" y="3" width="18" height="18" rx="2" opacity="0.6"/>
10890
+ <rect x="12" y="7" width="7" height="10" rx="1"/>
10891
+ </svg>
10892
+ </button>
10893
+ </div>
10894
+
10837
10895
  </div>
10838
10896
 
10839
10897
  </div>
@@ -11111,6 +11169,84 @@ class PanelText {
11111
11169
 
11112
11170
  this.builder.editor.onChange(); // this is because the changed element is in ContentBuilder scope
11113
11171
  });
11172
+ const btnTopSpacings = panel.querySelectorAll('[data-topspacing]');
11173
+ btnTopSpacings.forEach(btn => {
11174
+ btn.addEventListener('click', () => {
11175
+ this.saveForUndo();
11176
+ let elm = this.builder.controlpanel.activeElement;
11177
+ const val = btn.getAttribute('data-topspacing');
11178
+ panel.querySelectorAll('[data-topspacing]').forEach(btn => btn.classList.remove('active'));
11179
+ const spacing = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20];
11180
+ spacing.forEach(s => elm.classList.remove(`pt-${s}`));
11181
+
11182
+ if (val !== '') {
11183
+ elm.classList.add(`pt-${val}`);
11184
+ btn.classList.add('active');
11185
+ }
11186
+
11187
+ this.builder.editor.onChange();
11188
+ });
11189
+ });
11190
+ const btnBottomSpacings = panel.querySelectorAll('[data-bottomspacing]');
11191
+ btnBottomSpacings.forEach(btn => {
11192
+ btn.addEventListener('click', () => {
11193
+ this.saveForUndo();
11194
+ let elm = this.builder.controlpanel.activeElement;
11195
+ const val = btn.getAttribute('data-bottomspacing');
11196
+ panel.querySelectorAll('[data-bottomspacing]').forEach(btn => btn.classList.remove('active'));
11197
+ const spacing = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20];
11198
+ spacing.forEach(s => elm.classList.remove(`pb-${s}`));
11199
+
11200
+ if (val !== '') {
11201
+ elm.classList.add(`pb-${val}`);
11202
+ btn.classList.add('active');
11203
+ }
11204
+
11205
+ this.builder.editor.onChange();
11206
+ });
11207
+ });
11208
+ const inpMaxWidth = this.panel.querySelector('.inp-maxwidth');
11209
+ let debounceTimer;
11210
+ inpMaxWidth.addEventListener('input', () => {
11211
+ clearTimeout(debounceTimer);
11212
+ debounceTimer = setTimeout(() => {
11213
+ this.builder.editor.saveForUndo();
11214
+ let val = inpMaxWidth.value;
11215
+ let elm = this.builder.controlpanel.activeElement;
11216
+
11217
+ if (val !== '') {
11218
+ elm.style.maxWidth = val + 'px';
11219
+ } else {
11220
+ elm.style.maxWidth = '';
11221
+ }
11222
+
11223
+ this.builder.editor.onChange();
11224
+ }, 800);
11225
+ });
11226
+ const btnBlockCenters = panel.querySelectorAll('.btn-blockcenter');
11227
+ btnBlockCenters.forEach(btn => {
11228
+ btn.addEventListener('click', () => {
11229
+ this.saveForUndo();
11230
+ let elm = this.builder.controlpanel.activeElement;
11231
+ const val = btn.getAttribute('data-blockalign');
11232
+ panel.querySelectorAll('[data-blockalign]').forEach(btn => btn.classList.remove('active'));
11233
+
11234
+ if (val === 'left') {
11235
+ elm.style.marginLeft = '';
11236
+ elm.style.marginRight = 'auto';
11237
+ } else if (val === 'center') {
11238
+ elm.style.marginLeft = 'auto';
11239
+ elm.style.marginRight = 'auto';
11240
+ } else if (val === 'right') {
11241
+ elm.style.marginLeft = 'auto';
11242
+ elm.style.marginRight = '';
11243
+ }
11244
+
11245
+ btn.classList.add('active'); // this.builder.onChange();
11246
+
11247
+ this.builder.editor.onChange(); // this is because the changed element is in ContentBuilder scope
11248
+ });
11249
+ });
11114
11250
  }
11115
11251
 
11116
11252
  editorReady() {
@@ -11485,6 +11621,50 @@ class PanelText {
11485
11621
  }
11486
11622
 
11487
11623
  this.heading.closeOptions();
11624
+ this.panel.querySelectorAll('[data-blockalign]').forEach(btn => btn.classList.remove('active'));
11625
+ const inpMaxWidth = this.panel.querySelector('.inp-maxwidth');
11626
+ const maxWidth = activeElement.style.maxWidth;
11627
+
11628
+ if (maxWidth) {
11629
+ inpMaxWidth.value = parseInt(maxWidth);
11630
+
11631
+ if (activeElement.style.marginLeft === 'auto' && activeElement.style.marginRight === 'auto') {
11632
+ const btn = this.panel.querySelector('[data-blockalign="center"]');
11633
+ btn.classList.add('active');
11634
+ } else if (activeElement.style.marginLeft === 'auto') {
11635
+ const btn = this.panel.querySelector('[data-blockalign="right"]');
11636
+ btn.classList.add('active');
11637
+ } else {
11638
+ const btn = this.panel.querySelector('[data-blockalign="left"]');
11639
+ btn.classList.add('active');
11640
+ }
11641
+ } else {
11642
+ inpMaxWidth.value = '';
11643
+ }
11644
+
11645
+ this.panel.querySelectorAll('[data-topspacing]').forEach(btn => btn.classList.remove('active'));
11646
+ const spacing = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20]; // Find which spacing class is currently applied
11647
+
11648
+ let currentSpacing = spacing.find(s => activeElement.classList.contains(`pt-${s}`)); // If a spacing class is found, activate the corresponding button
11649
+
11650
+ if (currentSpacing !== undefined) {
11651
+ const btn = this.panel.querySelector(`[data-topspacing="${currentSpacing}"]`);
11652
+
11653
+ if (btn) {
11654
+ btn.classList.add('active');
11655
+ }
11656
+ }
11657
+
11658
+ this.panel.querySelectorAll('[data-bottomspacing]').forEach(btn => btn.classList.remove('active'));
11659
+ currentSpacing = spacing.find(s => activeElement.classList.contains(`pb-${s}`));
11660
+
11661
+ if (currentSpacing !== undefined) {
11662
+ const btn = this.panel.querySelector(`[data-bottomspacing="${currentSpacing}"]`);
11663
+
11664
+ if (btn) {
11665
+ btn.classList.add('active');
11666
+ }
11667
+ }
11488
11668
  }
11489
11669
 
11490
11670
  getStateTargeted() {
@@ -11611,6 +11791,61 @@ class PanelImage {
11611
11791
  <div>${out('Title')}:</div>
11612
11792
  <input type="text" class="inp-title" id="_inp_title_${this.random()}">
11613
11793
  </label>
11794
+
11795
+ <div>
11796
+ <div class="mb-1 mt-5">${out('Aspect Ratio')}:</div>
11797
+ <div class="group aspectratio w-full">
11798
+ <button title="21:9" data-aspectratio="21 / 9">21:9</button>
11799
+ <button title="16:9" data-aspectratio="16 / 9">16:9</button>
11800
+ <button title="3:2" data-aspectratio="3 / 2">3:2</button>
11801
+ <button title="4:3" data-aspectratio="4 / 3">4:3</button>
11802
+ <button title="5:4" data-aspectratio="5 / 4">5:4</button>
11803
+ <button title="1:1" data-aspectratio="1 / 1">1:1</button>
11804
+ <button title="4:5" data-aspectratio="4 / 5">4:5</button>
11805
+ <button title="3:4" data-aspectratio="3 / 4">3:4</button>
11806
+ <button title="2:3" data-aspectratio="2 / 3">2:3</button>
11807
+ <button title="9:16" data-aspectratio="9 / 16">9:16</button>
11808
+ <button title="9:21" data-aspectratio="9 / 21">9:21</button>
11809
+ <button title="${out('Clear')}" class="btn-clear" data-aspectratio=""><svg><use xlink:href="#icon-eraser"></use></svg></button>
11810
+ </div>
11811
+ </div>
11812
+
11813
+ <label>
11814
+ <div class="mt-2 mb-2">${out('Border Radius')}:</div>
11815
+ <div class="items-center">
11816
+ <input type="number" class="inp-borderradius" style="width:80px" min="0">&nbsp;
11817
+ <span>px</span>
11818
+ </div>
11819
+ </label>
11820
+
11821
+ <div>
11822
+ <div class="mb-1 mt-6">${out('Effects')}:</div>
11823
+ <div class="group imageeffect w-full">
11824
+ <button title="${out('Zoom')}" data-effect="scale-105" style="width: 105px;">Zoom</button>
11825
+ <button title="${out('Color')}" data-effect="grayscale-0" style="width: 105px;">Color</button>
11826
+ </div>
11827
+ </div>
11828
+
11829
+ <div>
11830
+ <div class="mb-1 mt-3">${out('Duration (s)')}:</div>
11831
+ <div class="group duration w-full">
11832
+ <!--<button title="75" data-duration="75">0.75</button>
11833
+ <button title="0.1" data-duration="100">0.1</button>
11834
+ <button title="0.15" data-duration="150">0.15</button>
11835
+ <button title="0.2" data-duration="200">0.2</button>
11836
+ <button title="0.3" data-duration="300">0.3</button>
11837
+ <button title="0.4" data-duration="400">0.4</button>-->
11838
+ <button title="0.5" data-duration="500">0.5</button>
11839
+ <!--<button title="0.6" data-duration="600">0.6</button>-->
11840
+ <button title="0.7" data-duration="700">0.7</button>
11841
+ <!--<button title="0.8" data-duration="800">0.8</button>
11842
+ <button title="0.9" data-duration="900">0.9</button>-->
11843
+ <button title="1" data-duration="1000">1</button>
11844
+ <!--<button title="1.2" data-duration="1200">1.2</button>-->
11845
+ <button title="1.5" data-duration="1500">1.5</button>
11846
+ <button title="${out('Clear')}" class="btn-clear" data-duration=""><svg><use xlink:href="#icon-eraser"></use></svg></button>
11847
+ </div>
11848
+ </div>
11614
11849
  </div>
11615
11850
  </div>
11616
11851
  `;
@@ -11675,6 +11910,184 @@ class PanelImage {
11675
11910
 
11676
11911
  this.builder.editor.onChange();
11677
11912
  });
11913
+ const btnAspectRatios = panel.querySelectorAll('[data-aspectratio]');
11914
+ btnAspectRatios.forEach(btn => {
11915
+ btn.addEventListener('click', () => {
11916
+ let img = this.builder.controlpanel.activeElement;
11917
+ const val = btn.getAttribute('data-aspectratio'); // let div = img.closest('.overflow-hidden');
11918
+
11919
+ const parent = img.parentNode;
11920
+ const grandparent = parent && parent.parentNode;
11921
+ let div = null;
11922
+
11923
+ if (parent && parent.classList.contains('overflow-hidden')) {
11924
+ div = parent;
11925
+ } else if (grandparent && grandparent.classList.contains('overflow-hidden')) {
11926
+ div = grandparent;
11927
+ }
11928
+
11929
+ if (val === '' && !img.classList.contains('hover:scale-105')) {
11930
+ // if not using scale effect
11931
+ // Clear button clicked - remove wrapper
11932
+ if (div) {
11933
+ // Check if image is wrapped in a link
11934
+ const link = div.querySelector('a');
11935
+
11936
+ if (link && link.contains(img)) {
11937
+ // Move link out of div, then remove div
11938
+ div.parentNode.insertBefore(link, div);
11939
+ div.remove();
11940
+ } else {
11941
+ // Move image out of div, then remove div
11942
+ div.parentNode.insertBefore(img, div);
11943
+ div.remove();
11944
+ } // Remove the aspect ratio classes from image
11945
+
11946
+
11947
+ img.classList.remove('w-full', 'h-full', 'object-cover');
11948
+ this.builder.editor.element.image.repositionImageTool();
11949
+ this.builder.editor.element.image.hideImageResizer();
11950
+ this.builder.editor.elmTool.repositionElementTool();
11951
+ }
11952
+ } else if (div) {
11953
+ div.style.aspectRatio = val;
11954
+ this.builder.editor.element.image.repositionImageTool();
11955
+ this.builder.editor.element.image.hideImageResizer();
11956
+ this.builder.editor.elmTool.repositionElementTool();
11957
+ } else {
11958
+ div = document.createElement('div');
11959
+ div.className = 'w-full overflow-hidden relative bg-gray-50';
11960
+ div.style.aspectRatio = val;
11961
+ img.classList.add('w-full', 'h-full', 'object-cover');
11962
+
11963
+ if (img.parentNode.tagName.toLowerCase() === 'a') {
11964
+ // Image is wrapped in a hyperlink
11965
+ const link = img.parentNode;
11966
+ link.parentNode.insertBefore(div, link); // Insert div before the link
11967
+
11968
+ div.appendChild(link); // Move link into div
11969
+ } else {
11970
+ img.parentNode.insertBefore(div, img); // Insert div before the img
11971
+
11972
+ div.appendChild(img); // Move img into div
11973
+ }
11974
+
11975
+ this.builder.editor.element.image.repositionImageTool();
11976
+ this.builder.editor.element.image.hideImageResizer();
11977
+ this.builder.editor.elmTool.repositionElementTool();
11978
+ }
11979
+
11980
+ panel.querySelectorAll('[data-aspectratio]').forEach(btn => btn.classList.remove('on'));
11981
+
11982
+ if (val !== '') {
11983
+ const btnSelected = panel.querySelector(`[data-aspectratio="${val}"]`);
11984
+ if (btnSelected) btnSelected.classList.add('on');
11985
+ }
11986
+ });
11987
+ });
11988
+ const btnEffects = panel.querySelectorAll('[data-effect]');
11989
+ btnEffects.forEach(btn => {
11990
+ btn.addEventListener('click', () => {
11991
+ let img = this.builder.controlpanel.activeElement;
11992
+ const val = btn.getAttribute('data-effect');
11993
+
11994
+ if (val === 'scale-105') {
11995
+ if (img.classList.contains('hover:scale-105')) {
11996
+ img.classList.remove('hover:scale-105');
11997
+ btn.classList.remove('active');
11998
+ } else {
11999
+ img.classList.add('hover:scale-105');
12000
+ btn.classList.add('active'); // If not wrapped in div, add it by clicking the clear button
12001
+
12002
+ const parent = img.parentNode;
12003
+ const grandparent = parent && parent.parentNode;
12004
+ let div = null;
12005
+
12006
+ if (parent && parent.classList.contains('overflow-hidden')) {
12007
+ div = parent;
12008
+ } else if (grandparent && grandparent.classList.contains('overflow-hidden')) {
12009
+ div = grandparent;
12010
+ }
12011
+
12012
+ if (!div) {
12013
+ const btnClear = panel.querySelector('[data-aspectratio=""]');
12014
+ if (btnClear) btnClear.click();
12015
+ }
12016
+ }
12017
+ }
12018
+
12019
+ if (val === 'grayscale-0') {
12020
+ if (img.classList.contains('hover:grayscale-0')) {
12021
+ img.classList.remove('grayscale');
12022
+ img.classList.remove('hover:grayscale-0');
12023
+ btn.classList.remove('active');
12024
+ } else {
12025
+ img.classList.add('grayscale');
12026
+ img.classList.add('hover:grayscale-0');
12027
+ btn.classList.add('active');
12028
+ }
12029
+ }
12030
+
12031
+ if (img.classList.contains('hover:scale-105') && img.classList.contains('hover:grayscale-0')) {
12032
+ img.classList.add('transition');
12033
+ img.classList.remove('transition-transform');
12034
+ } else if (img.classList.contains('hover:scale-105')) {
12035
+ img.classList.remove('transition');
12036
+ img.classList.add('transition-transform');
12037
+ } else if (img.classList.contains('hover:grayscale-0')) {
12038
+ img.classList.add('transition');
12039
+ img.classList.remove('transition-transform');
12040
+ } else {
12041
+ img.classList.remove('transition');
12042
+ img.classList.remove('transition-transform');
12043
+ }
12044
+ });
12045
+ });
12046
+ const btnDurations = panel.querySelectorAll('[data-duration]');
12047
+ btnDurations.forEach(btn => {
12048
+ btn.addEventListener('click', () => {
12049
+ let img = this.builder.controlpanel.activeElement;
12050
+ const val = btn.getAttribute('data-duration'); // Remove all existing duration classes
12051
+
12052
+ img.classList.remove('duration-75', 'duration-100', 'duration-150', 'duration-200', 'duration-300', 'duration-400', 'duration-500', 'duration-600', 'duration-700', 'duration-800', 'duration-900', 'duration-1000', 'duration-1200', 'duration-1500'); // Add the new duration class
12053
+
12054
+ if (val !== '') {
12055
+ img.classList.add('duration-' + val);
12056
+ }
12057
+
12058
+ panel.querySelectorAll('[data-duration]').forEach(btn => btn.classList.remove('on'));
12059
+
12060
+ if (val !== '') {
12061
+ const btnSelected = panel.querySelector(`[data-duration="${val}"]`);
12062
+ if (btnSelected) btnSelected.classList.add('on');
12063
+ }
12064
+ });
12065
+ });
12066
+ const inpBorderRadius = this.panel.querySelector('.inp-borderradius');
12067
+ inpBorderRadius.addEventListener('input', () => {
12068
+ this.builder.editor.saveForUndo();
12069
+ let val = inpBorderRadius.value;
12070
+ let img = this.builder.controlpanel.activeElement; // let div = img.closest('.overflow-hidden');
12071
+
12072
+ const parent = img.parentNode;
12073
+ const grandparent = parent && parent.parentNode;
12074
+ let div = null;
12075
+
12076
+ if (parent && parent.classList.contains('overflow-hidden')) {
12077
+ div = parent;
12078
+ } else if (grandparent && grandparent.classList.contains('overflow-hidden')) {
12079
+ div = grandparent;
12080
+ }
12081
+
12082
+ if (div) {
12083
+ div.style.borderRadius = val + 'px';
12084
+ } else {
12085
+ img.style.borderRadius = val + 'px';
12086
+ }
12087
+
12088
+ if (val === 0) img.style.borderRadius = '';
12089
+ this.builder.editor.onChange();
12090
+ });
11678
12091
  }
11679
12092
 
11680
12093
  editorReady() {
@@ -11732,6 +12145,56 @@ class PanelImage {
11732
12145
 
11733
12146
  const inpTitle = panel.querySelector('.inp-title');
11734
12147
  inpTitle.value = alt;
12148
+ const btnZoomEffect = panel.querySelector('[data-effect="scale-105"]');
12149
+
12150
+ if (img.classList.contains('hover:scale-105')) {
12151
+ btnZoomEffect.classList.add('active');
12152
+ } else {
12153
+ btnZoomEffect.classList.remove('active');
12154
+ }
12155
+
12156
+ const btnColorEffect = panel.querySelector('[data-effect="grayscale-0"]');
12157
+
12158
+ if (img.classList.contains('hover:grayscale-0')) {
12159
+ btnColorEffect.classList.add('active');
12160
+ } else {
12161
+ btnColorEffect.classList.remove('active');
12162
+ }
12163
+
12164
+ panel.querySelectorAll('[data-aspectratio]').forEach(btn => btn.classList.remove('on')); // const div = img.closest('.overflow-hidden');
12165
+
12166
+ const parent = img.parentNode;
12167
+ const grandparent = parent && parent.parentNode;
12168
+ let div = null;
12169
+
12170
+ if (parent && parent.classList.contains('overflow-hidden')) {
12171
+ div = parent;
12172
+ } else if (grandparent && grandparent.classList.contains('overflow-hidden')) {
12173
+ div = grandparent;
12174
+ }
12175
+
12176
+ if (div) {
12177
+ const aspectRatio = div.style.aspectRatio;
12178
+
12179
+ if (aspectRatio) {
12180
+ const btnSelected = panel.querySelector(`[data-aspectratio="${aspectRatio}"]`);
12181
+ btnSelected.classList.add('on');
12182
+ }
12183
+ }
12184
+
12185
+ panel.querySelectorAll('[data-duration]').forEach(btn => btn.classList.remove('on'));
12186
+ const durations = ['75', '100', '150', '200', '300', '400', '500', '600', '700', '800', '900', '1000', '1200', '1500'];
12187
+ const currentDuration = durations.find(d => img.classList.contains(`duration-${d}`));
12188
+
12189
+ if (currentDuration) {
12190
+ const btnSelected = panel.querySelector(`[data-duration="${currentDuration}"]`);
12191
+ btnSelected.classList.add('on');
12192
+ }
12193
+
12194
+ const inpBorderRadius = this.panel.querySelector('.inp-borderradius');
12195
+ const targetElement = div || img;
12196
+ const borderRadius = targetElement.style.borderRadius;
12197
+ inpBorderRadius.value = parseInt(borderRadius) || 0;
11735
12198
  }
11736
12199
 
11737
12200
  updateImageSrc(src) {
@@ -17439,7 +17902,7 @@ class PanelSection {
17439
17902
  const s = btn.getAttribute('data-height');
17440
17903
  this.section.setSectionHeight(s);
17441
17904
  btnHeight.forEach(btn => btn.classList.remove('on'));
17442
- if (s !== '') btn.classList.add('on');
17905
+ if (s !== '0') btn.classList.add('on');
17443
17906
  });
17444
17907
  });
17445
17908
  const btnSpacing = panel.querySelectorAll('[data-spacing]');
@@ -17519,7 +17982,7 @@ class PanelSection {
17519
17982
  const s = btn.getAttribute('data-animstart');
17520
17983
  this.section.sectionAnimStart(s);
17521
17984
  btnAnimStart.forEach(btn => btn.classList.remove('on'));
17522
- btn.classList.add('on');
17985
+ if (s !== '') btn.classList.add('on');
17523
17986
  });
17524
17987
  });
17525
17988
  const btnAnimEnd = panel.querySelectorAll('[data-animend]');
@@ -17528,7 +17991,7 @@ class PanelSection {
17528
17991
  const s = btn.getAttribute('data-animend');
17529
17992
  this.section.sectionAnimEnd(s);
17530
17993
  btnAnimEnd.forEach(btn => btn.classList.remove('on'));
17531
- btn.classList.add('on');
17994
+ if (s !== '') btn.classList.add('on');
17532
17995
  });
17533
17996
  }); // Scroll Button
17534
17997
 
@@ -17538,7 +18001,7 @@ class PanelSection {
17538
18001
  const s = btn.getAttribute('data-scrollpreset');
17539
18002
  this.section.sectionScrollPreset(s);
17540
18003
  btnScrollPreset.forEach(btn => btn.classList.remove('on'));
17541
- btn.classList.add('on');
18004
+ if (s !== '') btn.classList.add('on');
17542
18005
  });
17543
18006
  }); // Responsive
17544
18007
 
@@ -33334,8 +33797,8 @@ class Util$1 {
33334
33797
  if (plugin) {
33335
33798
  element.insertAdjacentHTML('afterend', html);
33336
33799
  newelement = element.nextElementSibling;
33337
- } else if (!element.nextElementSibling && !element.closest('[data-subblock]')) {
33338
- // active element is div.display > p.
33800
+ } else if (!element.nextElementSibling && element.closest('.display')) {
33801
+ /*if(!element.nextElementSibling && !element.closest('[data-subblock]')) { // active element is div.display > p. */
33339
33802
  let activeCol = this.builder.activeCol;
33340
33803
  let current;
33341
33804
  const elms = dom.elementChildren(activeCol);
@@ -74764,11 +75227,17 @@ class Image$1 {
74764
75227
  }
74765
75228
  const newPos = util.getElementPosition(elm);
74766
75229
  let scaleX = newPos.scaleX;
75230
+ let extraScaleX = this.getScale(elm).scaleX;
75231
+ let extraScaleY = this.getScale(elm).scaleX;
74767
75232
  imageTool.style.display = 'flex';
74768
75233
  let _toolwidth = imageTool.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
74769
75234
 
74770
- let w = elm.offsetWidth * scaleX * this.builder.opts.zoom;
74771
- let top = newPos.top + window.pageYOffset;
75235
+ let w = elm.offsetWidth * extraScaleX * scaleX * this.builder.opts.zoom;
75236
+ let h = elm.offsetHeight * extraScaleY * scaleX * this.builder.opts.zoom;
75237
+
75238
+ // Compensate for the vertical shift caused by scaling
75239
+ let scaleShiftY = (h - elm.offsetHeight * scaleX * this.builder.opts.zoom) / 2;
75240
+ let top = newPos.top + window.pageYOffset + scaleShiftY;
74772
75241
  let left = newPos.left + window.pageXOffset;
74773
75242
  let toolLeft = left + (w / 2 - _toolwidth / 2);
74774
75243
 
@@ -74782,7 +75251,10 @@ class Image$1 {
74782
75251
  }
74783
75252
  imageTool.style.top = top + 'px';
74784
75253
  imageTool.style.left = toolLeft + 'px';
74785
- if (!this.builder.activeImage.hasAttribute('data-noresize') && (this.builder.imageResizeOnBlock || !this.builder.activeImage.closest('.is-block'))) {
75254
+ const parent = elm.parentNode;
75255
+ const grandparent = parent && parent.parentNode;
75256
+ const hasWrapper = parent && parent.classList.contains('overflow-hidden') || grandparent && grandparent.classList.contains('overflow-hidden');
75257
+ if (!hasWrapper && !this.builder.activeImage.hasAttribute('data-noresize') && (this.builder.imageResizeOnBlock || !this.builder.activeImage.closest('.is-block'))) {
74786
75258
  let imageResizer = this.imageResizer;
74787
75259
  imageResizer.style.top = top + 'px';
74788
75260
  imageResizer.style.left = left + 'px';
@@ -74818,6 +75290,21 @@ class Image$1 {
74818
75290
  if (imageTool) imageTool.style.display = '';
74819
75291
  this.hideImageResizer();
74820
75292
  }
75293
+ getScale(element) {
75294
+ const computedStyle = window.getComputedStyle(element);
75295
+ const transform = computedStyle.transform;
75296
+ if (!transform || transform === 'none') {
75297
+ return {
75298
+ scaleX: 1,
75299
+ scaleY: 1
75300
+ };
75301
+ }
75302
+ const matrix = new DOMMatrix(transform);
75303
+ return {
75304
+ scaleX: matrix.a,
75305
+ scaleY: matrix.d
75306
+ };
75307
+ }
74821
75308
  click(e) {
74822
75309
  const util = this.builder.util;
74823
75310
  const dom = this.builder.dom;
@@ -74843,13 +75330,19 @@ class Image$1 {
74843
75330
  }
74844
75331
  const newPos = util.getElementPosition(elm);
74845
75332
  let scaleX = newPos.scaleX;
75333
+ let extraScaleX = this.getScale(elm).scaleX;
75334
+ let extraScaleY = this.getScale(elm).scaleX;
74846
75335
  this.renderTool();
74847
75336
  let imageTool = this.imageTool;
74848
75337
  imageTool.style.display = 'flex';
74849
75338
  let _toolwidth = imageTool.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
74850
75339
 
74851
- let w = elm.offsetWidth * scaleX * this.builder.opts.zoom;
74852
- let top = newPos.top + window.pageYOffset;
75340
+ let w = elm.offsetWidth * extraScaleX * scaleX * this.builder.opts.zoom;
75341
+ let h = elm.offsetHeight * extraScaleY * scaleX * this.builder.opts.zoom;
75342
+
75343
+ // Compensate for the vertical shift caused by scaling
75344
+ let scaleShiftY = (h - elm.offsetHeight * scaleX * this.builder.opts.zoom) / 2;
75345
+ let top = newPos.top + window.pageYOffset + scaleShiftY;
74853
75346
  let left = newPos.left + window.pageXOffset;
74854
75347
  let toolLeft = left + (w / 2 - _toolwidth / 2);
74855
75348
 
@@ -74863,9 +75356,12 @@ class Image$1 {
74863
75356
  }
74864
75357
  imageTool.style.top = top + 'px';
74865
75358
  imageTool.style.left = toolLeft + 'px';
75359
+ const parent = elm.parentNode;
75360
+ const grandparent = parent && parent.parentNode;
75361
+ const hasWrapper = parent && parent.classList.contains('overflow-hidden') || grandparent && grandparent.classList.contains('overflow-hidden');
74866
75362
 
74867
75363
  // Image Resizer
74868
- if (!elm.hasAttribute('data-noresize') && (this.builder.imageResizeOnBlock || !elm.closest('.is-block'))) {
75364
+ if (!hasWrapper && !elm.hasAttribute('data-noresize') && (this.builder.imageResizeOnBlock || !elm.closest('.is-block'))) {
74869
75365
  let imageResizer = this.imageResizer;
74870
75366
  const newPos = util.getElementPosition(elm);
74871
75367
  let top = newPos.top + window.pageYOffset;
@@ -74894,33 +75390,6 @@ class Image$1 {
74894
75390
  if (this.builder.moveable) this.builder.moveable.updateRect();
74895
75391
  const movControlBox = document.querySelector('.moveable-control-box');
74896
75392
  if (movControlBox && !this.builder.hideImageResizer) movControlBox.style.display = 'block';
74897
-
74898
- /*
74899
- const handleImageToolClickOut = e =>{
74900
- let elm = e.target;
74901
- if(!elm) return;
74902
- if(!elm.closest('#divImageResizer') && !elm.closest('#divImageTool') &&
74903
- !elm.closest('.is-modal') && !elm.closest('.keep-selection') &&
74904
- !elm.closest('.sl-wrapper') && !elm.closest('.sl-overlay') && !elm.closest('.sl-close') &&
74905
- !elm.closest('img')) { // click outside
74906
-
74907
- // hide
74908
- this.hideImageTool();
74909
- document.removeEventListener('click', handleImageToolClickOut);
74910
- if(this.builder.iframeDocument) {
74911
- this.builder.doc.removeEventListener('click', handleImageToolClickOut);
74912
- }
74913
- this.builder.handleImageToolClickOut_=false;
74914
- }
74915
- };
74916
- if(!this.builder.handleImageToolClickOut_) {
74917
- document.addEventListener('click', handleImageToolClickOut);
74918
- if(this.builder.iframeDocument) {
74919
- this.builder.doc.addEventListener('click', handleImageToolClickOut);
74920
- }
74921
- this.builder.handleImageToolClickOut_=true;
74922
- }
74923
- */
74924
75393
  } else {
74925
75394
  let imageResizer = this.imageResizer;
74926
75395
  imageResizer.style.display = 'none';
@@ -118015,12 +118484,16 @@ OUT OF SCOPE requests include:
118015
118484
  ${imageGenEnabled ? '' : '- AI image generation (currently disabled - but external images are OK)'}
118016
118485
 
118017
118486
  IMPORTANT DISTINCTION:
118018
- - "Tell me about the weather in general" → VALID (chat/education)
118019
118487
  - "What's the weather in Tokyo right now?" → INVALID (requires real-time data)
118020
- - "Write a story about space" → VALID (chat/creative)
118488
+ - "Tell me about the weather in general" → VALID (chat task)
118021
118489
  - "Generate a video about space" → INVALID (video generation)
118022
- - "Explain how databases work" → VALID (chat/education)
118490
+ - "Write a story about space" → VALID (chat task)
118023
118491
  - "Create a database for me" → INVALID (database operations)
118492
+ - "Explain how databases work" → VALID (chat task)
118493
+ - "How would you design this?" → VALID (chat task)
118494
+ - "I need help with..." → VALID (chat task)
118495
+
118496
+ NOTE: Conversational requests, questions, and vague requests are ALL VALID and should be classified as "chat" tasks.
118024
118497
 
118025
118498
  Respond with a JSON object in this exact format:
118026
118499
  {
@@ -118045,6 +118518,15 @@ Task type definitions:
118045
118518
  - "chat": Conversations, questions, explanations, advice, discussions
118046
118519
  ${imageGenEnabled ? '- "image": Generate AI images and integrate them into the page' : ''}
118047
118520
 
118521
+ FALLBACK RULE:
118522
+ - If the request is vague, conversational, or doesn't clearly require code/image generation
118523
+ - If you're uncertain about how to categorize it
118524
+ - If it's a general question or discussion
118525
+ - If it seems like the user wants advice, help, or guidance
118526
+ → Create a single "chat" task with the original user message
118527
+
118528
+ CRITICAL: NEVER return an empty tasks array. When in doubt, use "chat".
118529
+
118048
118530
  CODE TASK RULES:
118049
118531
  - ALWAYS combine multiple code-related instructions into ONE code task
118050
118532
  - The AI can handle complex, multi-part code generation in a single task
@@ -118372,6 +118854,11 @@ ${isMixed ? 'CRITICAL: Only perform the task specified above. Do not answer othe
118372
118854
 
118373
118855
  const system = `You are a helpful AI assistant for a web builder tool. You can answer questions about web development, design, HTML, CSS, JavaScript, and provide general assistance.
118374
118856
 
118857
+ When providing code examples:
118858
+ - Use markdown code blocks with language tags: \`\`\`html, \`\`\`css, \`\`\`javascript
118859
+ - Use inline code for short snippets: \`<element>\`
118860
+ - Never output raw HTML that could be rendered by the browser
118861
+
118375
118862
  ${isMixed ? `CRITICAL INSTRUCTION: You are handling ONE SPECIFIC TASK from a multi-part request.
118376
118863
 
118377
118864
  Your ONLY task is: ${task.description}
@@ -118728,6 +119215,14 @@ ${this.builder.html()}
118728
119215
  } else {
118729
119216
  this.builder.uo.saveForUndo();
118730
119217
  }
119218
+ const parser = new DOMParser();
119219
+ const doc = parser.parseFromString(code, 'text/html');
119220
+ const containers = doc.querySelectorAll('div.is-container');
119221
+ containers.forEach(container => {
119222
+ container.classList.add('size-17', 'leading-17'); // add default font-size & line-height
119223
+ });
119224
+
119225
+ code = doc.body.innerHTML;
118731
119226
  this.builder.loadHtml(code);
118732
119227
  }
118733
119228
  escapeHtml(text) {
@@ -119271,11 +119766,13 @@ Classes: p-0, p-2, p-3, p-4, p-6, p-8, p-10, p-12
119271
119766
  **Example: Card with padding**
119272
119767
 
119273
119768
  <!-- Example: Card with padding -->
119274
- <div class="p-12 bg-gray-50">
119769
+ <div class="p-12 box-border bg-gray-50">
119275
119770
  <p class="size-18 pb-4">Card content</p>
119276
119771
  <p class="size-14 text-gray-600">Description</p>
119277
119772
  </div>
119278
119773
 
119774
+ **Key classes:** p-X, box-border (always use box-border with padding on DIV or cards)
119775
+
119279
119776
  ### Directional Padding
119280
119777
 
119281
119778
  Classes: px-4, py-4, pt-4, pb-4, pl-4, pr-4
@@ -119432,7 +119929,7 @@ border-2 border-solid mt-2 mb-1 font-normal tracking-normal rounded-full
119432
119929
  </a>
119433
119930
  </div>
119434
119931
 
119435
- **Key classes:** 'underline' + 'border-transparent' (no horizontal padding needed).
119932
+ **Key classes:** 'underline'+ 'underline-offset-4' + 'border-transparent' (no horizontal padding needed).
119436
119933
 
119437
119934
  **For button groups:**
119438
119935
 
@@ -119508,8 +120005,7 @@ Use grayscale for minimalist design.
119508
120005
  > **Editorial Style:** Stick to black, white, and grays for a clean, minimalist aesthetic. Use color sparingly for accents.
119509
120006
 
119510
120007
  ` + `
119511
-
119512
- ### Animation
120008
+ ## Animation
119513
120009
 
119514
120010
  **Transition**
119515
120011
 
@@ -119517,80 +120013,117 @@ Classes: transition-none, transition, transition-colors, transition-opacity, tra
119517
120013
 
119518
120014
  **Duration**
119519
120015
 
119520
- Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000, duration-1500
120016
+ Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-400, duration-500, duration-600, duration-700, duration-800, duration-900, duration-1000, duration-1500
119521
120017
 
119522
120018
  **Timing**
119523
120019
 
119524
120020
  Classes: ease-linear, ease-in, ease-out, ease-in-out
119525
120021
 
119526
- **Delay**
120022
+ **Hover Transforms**
119527
120023
 
119528
- Classes: delay-75, delay-100, delay-150, delay-200, delay-300, delay-500
120024
+ Classes: hover:scale-105, hover:-translate-y-1, hover:-translate-y-2
119529
120025
 
119530
- **Scale**
120026
+ **Hover Shadow**
119531
120027
 
119532
- Classes: scale-0, scale-50, scale-75, scale-90, scale-95, scale-100, scale-105, scale-110, scale-125, scale-150
120028
+ Classes: hover:shadow-sm, hover:shadow, hover:shadow-md, hover:shadow-lg, hover:shadow-xl, hover:shadow-2xl
119533
120029
 
119534
- **Hover Effect**
120030
+ **Hover Background Colors**
119535
120031
 
119536
- Classes: hover:scale-105
120032
+ Classes: hover:bg-white, hover:bg-black, hover:bg-gray-50, hover:bg-gray-100, hover:bg-gray-200, hover:bg-gray-300, hover:bg-gray-400, hover:bg-gray-500, hover:bg-gray-600, hover:bg-gray-700, hover:bg-gray-800, hover:bg-gray-900, hover:bg-transparent
119537
120033
 
119538
- **Rotate**
120034
+ **Hover Text Colors**
119539
120035
 
119540
- Classes: rotate-0, rotate-45, rotate-90, rotate-180
120036
+ Classes: hover:text-white, hover:text-black, hover:text-current, hover:text-gray-50, hover:text-gray-100, hover:text-gray-200, hover:text-gray-300, hover:text-gray-400, hover:text-gray-500, hover:text-gray-600, hover:text-gray-700, hover:text-gray-800, hover:text-gray-900, hover:text-gray-950
119541
120037
 
119542
- **Translate X**
120038
+ **Hover Opacity**
119543
120039
 
119544
- Classes: translate-x-0, translate-x-1, translate-x-2, translate-x-4, translate-x-8
120040
+ Classes: hover:opacity-70, hover:opacity-75, hover:opacity-80, hover:opacity-90, hover:opacity-95, hover:opacity-100
119545
120041
 
119546
- **Translate Y**
120042
+ **Animation keyframes**
119547
120043
 
119548
- Classes: translate-y-0, translate-y-1, translate-y-2, translate-y-4, translate-y-8
120044
+ Classes: spin, ping, pulse, bounce
119549
120045
 
119550
- **Skew**
120046
+ ### Animation Examples
119551
120047
 
119552
- Classes: skew-x-0, skew-x-3, skew-x-6, skew-y-0, skew-y-3, skew-y-6
120048
+ **Example: Hover lift on Cards**
119553
120049
 
119554
- **Overflow**
120050
+ <div class="row" style="gap: 30px;">
120051
+ <div class="column">
120052
+ <!-- card -->
120053
+ <div class="p-10 box-border bg-white h-full transition-transform duration-300 hover:-translate-y-2" style="border: 1px solid #e0e0e0;">
120054
+ <div class="mb-6 text-gray-300"><i class="bi bi-star-fill"></i><i class="bi bi-star-fill"></i><i class="bi bi-star-fill"></i><i class="bi bi-star-fill"></i><i class="bi bi-star-fill"></i></div>
120055
+ <p class="size-18 leading-16 mb-8 text-gray-800">"It's rare to find a tool that balances power with simplicity so effectively. It has completely streamlined our workflow."</p>
120056
+ <p class="size-13 font-bold uppercase tracking-widest">Freja E. — Company</p>
120057
+ </div>
120058
+ </div>
120059
+ <div class="column">
120060
+ <!-- card -->
120061
+ </div>
120062
+ <div class="column">
120063
+ <!-- card -->
120064
+ </div>
120065
+ </div>
119555
120066
 
119556
- Classes: overflow-hidden, overflow-visible, overflow-scroll, overflow-auto
120067
+ **Key classes:** transition-transform, duration-300, hover:translate-y--2
119557
120068
 
119558
- **Opacity**
120069
+ **Example: Hover lift and shadow on Cards**
119559
120070
 
119560
- Classes:
120071
+ <div class="row" style="gap: 30px;">
120072
+ <div class="column">
120073
+ <!-- card -->
120074
+ <div class="p-10 box-border bg-white transition-all duration-300 ease-out hover:-translate-y-2 hover:shadow-xl" style="border: 1px solid #e5e5e5;">
120075
+ <!-- card content -->
120076
+ </div>
120077
+ </div>
120078
+ <div class="column">
120079
+ <!-- card -->
120080
+ </div>
120081
+ <div class="column">
120082
+ <!-- card -->
120083
+ </div>
120084
+ </div>
119561
120085
 
119562
- | Class | Color |
119563
- | ------------ | ------------- |
119564
- | '.opacity-0' | opacity: 0 |
119565
- | '.opacity-2' | opacity: 0.02 |
119566
- | '.opacity-4' | opacity: 0.04 |
119567
- | '.opacity-5' | opacity: 0.05 |
119568
- | '.opacity-6' | opacity: 0.06 |
119569
- | '.opacity-8' | opacity: 0.07 |
119570
- | '.opacity-10' | opacity: 0.1 |
119571
- | '.opacity-12' | opacity: 0.12 |
119572
- | '.opacity-15' | opacity: 0.15 |
119573
- | '.opacity-20' | opacity: 0.2 |
119574
- | '.opacity-25' | opacity: 0.25 |
119575
- | '.opacity-30' | opacity: 0.3 |
119576
- | '.opacity-35' | opacity: 0.35 |
119577
- | '.opacity-40' | opacity: 0.4 |
119578
- | '.opacity-45' | opacity: 0.45 |
119579
- | '.opacity-50' | opacity: 0.5 |
119580
- | '.opacity-55' | opacity: 0.55 |
119581
- | '.opacity-60' | opacity: 0.6 |
119582
- | '.opacity-65' | opacity: 0.65 |
119583
- | '.opacity-70' | opacity: 0.7 |
119584
- | '.opacity-75' | opacity: 0.75 |
119585
- | '.opacity-80' | opacity: 0.8 |
119586
- | '.opacity-85' | opacity: 0.85 |
119587
- | '.opacity-90' | opacity: 0.9 |
119588
- | '.opacity-95' | opacity: 0.95 |
119589
- | '.opacity-100' | opacity: 1 |
120086
+ **Key classes:** transition-all duration-300 ease-out hover:-translate-y-2 hover:shadow-xl
119590
120087
 
119591
- **Animation keyframes**
120088
+ **Example: Hover zoom on Cards**
119592
120089
 
119593
- Classes: spin, ping, pulse, bounce
120090
+ <div class="row" style="gap: 30px;">
120091
+ <div class="column">
120092
+ <!-- card -->
120093
+ <div class="p-12 box-border bg-white h-full flex flex-col items-center text-center transition-transform duration-300 ease-out hover:scale-105" style="box-shadow: 0 10px 40px -10px rgba(0,0,0,0.05);">
120094
+ <!-- card content -->
120095
+ </div>
120096
+ </div>
120097
+ <div class="column">
120098
+ <!-- card -->
120099
+ </div>
120100
+ <div class="column">
120101
+ <!-- card -->
120102
+ </div>
120103
+ </div>
120104
+
120105
+ **Key classes:** transition-transform, duration-300, ease-out, hover:scale-105
120106
+
120107
+ **Example: Hover zoom on Images**
120108
+
120109
+ <div class="row" style="gap:40px;">
120110
+ <div class="column">
120111
+ <div class="w-full overflow-hidden relative bg-gray-50 mb-6" style="aspect-ratio: 4 / 3;">
120112
+ <img src="image1.jpg" alt="Freja E. Andersen" class="w-full h-full object-cover transition-transform hover:scale-105 duration-1000">
120113
+ </div>
120114
+ <h4 class="size-20 font-normal">Freja E. Andersen</h4>
120115
+ <p class="size-14 text-gray-500 uppercase tracking-wide mt-1 mb-3">Lead Architect</p>
120116
+ <p class="size-15 text-gray-600 leading-16">Specializing in sustainable residential architecture with a focus on natural light.</p>
120117
+ </div>
120118
+ <div class="column">
120119
+
120120
+ </div>
120121
+ <div class="column">
120122
+
120123
+ </div>
120124
+ </div>
120125
+
120126
+ **Key classes:** transition-transform, hover:scale-105, duration-1000 (or use duration-1500 for larger image)
119594
120127
  ` + `
119595
120128
  ---
119596
120129
  ` + `
@@ -119613,7 +120146,7 @@ Classes: spin, ping, pulse, bounce
119613
120146
 
119614
120147
  ### Card with Padding
119615
120148
 
119616
- <div class="p-12 bg-gray-50">
120149
+ <div class="p-12 box-border bg-gray-50">
119617
120150
  <p class="size-18 leading-17 text-black pb-4">
119618
120151
  Card title or content
119619
120152
  </p>
@@ -119660,16 +120193,18 @@ Classes: spin, ping, pulse, bounce
119660
120193
  </div>
119661
120194
  <div class="row">
119662
120195
  <div class="column">
119663
- <img class="pb-2" src="https://placehold.co/400x400/f5f5f5/999?text=Alex+T" alt="Team Member">
120196
+ <div class="w-full overflow-hidden relative bg-gray-50 mb-2" style="aspect-ratio: 4 / 3;">
120197
+ <img src="image1.jpg" alt="Freja E. Andersen" class="w-full h-full object-cover transition-transform hover:scale-105 duration-1000">
120198
+ </div>
119664
120199
  <h4 class="size-18 font-medium pb-2 text-center">Alex Thompson</h4>
119665
120200
  <p class="size-12 uppercase tracking-150 text-gray-500 pb-3 text-center">Founder &amp; CEO</p>
119666
120201
  <p class="size-15 leading-16 text-gray-600 text-center">Visionary leader with 15 years of experience.</p>
119667
120202
  </div>
119668
120203
  <div class="column">
119669
- <img class="pb-2" src="https://placehold.co/400x400/f5f5f5/999?text=Sophia+M" alt="Team Member">
119670
- <h4 class="size-18 font-medium pb-2 text-center">Sophia Martinez</h4>
119671
- <p class="size-12 uppercase tracking-150 text-gray-500 pb-3 text-center">CTO</p>
119672
- <p class="size-15 leading-16 text-gray-600 text-center">Technical architect building systems.</p>
120204
+ <!-- Next image -->
120205
+ </div>
120206
+ <div class="column">
120207
+ <!-- Next image -->
119673
120208
  </div>
119674
120209
  </div>
119675
120210
 
@@ -123067,6 +123602,10 @@ class ContentBuilder {
123067
123602
  const style = window.getComputedStyle(row);
123068
123603
  const gapValue = parseFloat(style.gap) || 0;
123069
123604
  const columns = row.querySelectorAll('.column');
123605
+ columns.forEach(col => {
123606
+ if (col.style.width === '100%') col.style.width = ''; // cleanup
123607
+ });
123608
+
123070
123609
  let allHaveWidth = true;
123071
123610
  let totalWidthPercent = 0;
123072
123611
  columns.forEach(col => {
@@ -123209,6 +123748,7 @@ class ContentBuilder {
123209
123748
  if (e.target.closest('[data-html]')) return; // normal paste
123210
123749
 
123211
123750
  e.preventDefault();
123751
+ e.stopPropagation();
123212
123752
  let clipboardDataText = (e.clipboardData || window.clipboardData).getData('text');
123213
123753
  let clipboardDataHtml = (e.clipboardData || window.clipboardData).getData('text/html');
123214
123754
  if (clipboardDataHtml.trim() === '') clipboardDataHtml = clipboardDataText;
@@ -126185,7 +126725,9 @@ Please obtain a license at: https://innovastudio.com/contentbox`);
126185
126725
  if (!this.controlPanel) this.rte.click(col);
126186
126726
  }
126187
126727
  handleCellClick(col, e) {
126188
- if (col !== e.target.closest('.column')) return;
126728
+ if (this.useDefaultGrid) {
126729
+ if (col !== e.target.closest('.column')) return;
126730
+ }
126189
126731
  if (this.cleanEditing) {
126190
126732
  col.parentNode.querySelector('.is-row-tool').style.display = '';
126191
126733
  col.parentNode.querySelector('.is-col-tool').style.display = '';
@@ -141281,9 +141823,9 @@ class Box {
141281
141823
  if (checked) {
141282
141824
  overlay.style.filter = 'grayscale(1)';
141283
141825
  } else {
141284
- if (overlayBg && overlayBg.style.filter) overlayBg.style.filter = overlayBg.style.filter.replace('grayscale(1)', ''); // backward
141826
+ if (overlayBg && overlayBg.style.filter) overlayBg.style.filter = overlayBg.style.filter.replace('grayscale(1)', '').replace('grayscale(100%)', ''); // backward
141285
141827
 
141286
- if (overlay.style.filter) overlay.style.filter = overlay.style.filter.replace('grayscale(1)', '');
141828
+ if (overlay.style.filter) overlay.style.filter = overlay.style.filter.replace('grayscale(1)', '').replace('grayscale(100%)', '');
141287
141829
  }
141288
141830
  }
141289
141831
 
@@ -141503,16 +142045,15 @@ class Box {
141503
142045
  if (s === '19') container.classList.add('size-19');
141504
142046
  if (s === '20') container.classList.add('size-20');
141505
142047
  if (s === '21') container.classList.add('size-21'); // cleanup
141506
-
141507
- let elms = container.querySelectorAll('.size-16,.size-17,.size-18,.size-19,.size-20,.size-21');
141508
- elms.forEach(elm => {
141509
- elm.classList.remove('size-16');
141510
- elm.classList.remove('size-17');
141511
- elm.classList.remove('size-18');
141512
- elm.classList.remove('size-19');
141513
- elm.classList.remove('size-20');
141514
- elm.classList.remove('size-21');
141515
- });
142048
+ // let elms = container.querySelectorAll('.size-16,.size-17,.size-18,.size-19,.size-20,.size-21');
142049
+ // elms.forEach(elm=>{
142050
+ // elm.classList.remove('size-16');
142051
+ // elm.classList.remove('size-17');
142052
+ // elm.classList.remove('size-18');
142053
+ // elm.classList.remove('size-19');
142054
+ // elm.classList.remove('size-20');
142055
+ // elm.classList.remove('size-21');
142056
+ // });
141516
142057
  });
141517
142058
  this.builder.onChange();
141518
142059
  }
@@ -141544,21 +142085,20 @@ class Box {
141544
142085
  if (s === '1.8') container.classList.add('leading-18');
141545
142086
  if (s === '1.9') container.classList.add('leading-19');
141546
142087
  if (s === '2') container.classList.add('leading-20'); // cleanup
141547
-
141548
- let elms = container.querySelectorAll('.leading-none,.leading-11,.leading-12,.leading-13,.leading-14,.leading-15,.leading-16,.leading-17,.leading-18,.leading-19,.leading-20');
141549
- elms.forEach(elm => {
141550
- elm.classList.remove('leading-none');
141551
- elm.classList.remove('leading-11');
141552
- elm.classList.remove('leading-12');
141553
- elm.classList.remove('leading-13');
141554
- elm.classList.remove('leading-14');
141555
- elm.classList.remove('leading-15');
141556
- elm.classList.remove('leading-16');
141557
- elm.classList.remove('leading-17');
141558
- elm.classList.remove('leading-18');
141559
- elm.classList.remove('leading-19');
141560
- elm.classList.remove('leading-20');
141561
- });
142088
+ // let elms = container.querySelectorAll('.leading-none,.leading-11,.leading-12,.leading-13,.leading-14,.leading-15,.leading-16,.leading-17,.leading-18,.leading-19,.leading-20');
142089
+ // elms.forEach(elm=>{
142090
+ // elm.classList.remove('leading-none');
142091
+ // elm.classList.remove('leading-11');
142092
+ // elm.classList.remove('leading-12');
142093
+ // elm.classList.remove('leading-13');
142094
+ // elm.classList.remove('leading-14');
142095
+ // elm.classList.remove('leading-15');
142096
+ // elm.classList.remove('leading-16');
142097
+ // elm.classList.remove('leading-17');
142098
+ // elm.classList.remove('leading-18');
142099
+ // elm.classList.remove('leading-19');
142100
+ // elm.classList.remove('leading-20');
142101
+ // });
141562
142102
  });
141563
142103
  this.builder.onChange();
141564
142104
  } // Content
@@ -142419,6 +142959,8 @@ class Box {
142419
142959
  overlayColor = overlayBg.querySelector('.is-overlay-color');
142420
142960
  }
142421
142961
 
142962
+ if (overlayBg) overlayBg.style.opacity = ''; // clear unwanted opacity
142963
+
142422
142964
  if (this.builder.useCssClasses) {
142423
142965
  const classes = this.builder.cssClasses.opacity;
142424
142966
 
@@ -145727,8 +146269,13 @@ class CodeChat {
145727
146269
  let isChatVisible = savedState === 'true'; // Only open if explicitly set to 'true'
145728
146270
 
145729
146271
  if (!isChatVisible) {
145730
- modal.classList.add('hidden');
145731
- modal.setAttribute('aria-hidden', 'true');
146272
+ if (this.builder.startCodeChat) {
146273
+ modal.classList.remove('hidden');
146274
+ modal.removeAttribute('aria-hidden');
146275
+ } else {
146276
+ modal.classList.add('hidden');
146277
+ modal.setAttribute('aria-hidden', 'true');
146278
+ }
145732
146279
  } else {
145733
146280
  modal.classList.remove('hidden');
145734
146281
  modal.removeAttribute('aria-hidden');
@@ -146547,12 +147094,16 @@ OUT OF SCOPE requests include:
146547
147094
  ${imageGenEnabled ? '' : '- AI image generation (currently disabled - but external images are OK)'}
146548
147095
 
146549
147096
  IMPORTANT DISTINCTION:
146550
- - "Tell me about the weather in general" → VALID (chat/education)
146551
147097
  - "What's the weather in Tokyo right now?" → INVALID (requires real-time data)
146552
- - "Write a story about space" → VALID (chat/creative)
147098
+ - "Tell me about the weather in general" → VALID (chat task)
146553
147099
  - "Generate a video about space" → INVALID (video generation)
146554
- - "Explain how databases work" → VALID (chat/education)
147100
+ - "Write a story about space" → VALID (chat task)
146555
147101
  - "Create a database for me" → INVALID (database operations)
147102
+ - "Explain how databases work" → VALID (chat task)
147103
+ - "How would you design this?" → VALID (chat task)
147104
+ - "I need help with..." → VALID (chat task)
147105
+
147106
+ NOTE: Conversational requests, questions, and vague requests are ALL VALID and should be classified as "chat" tasks.
146556
147107
 
146557
147108
  Respond with a JSON object in this exact format:
146558
147109
  {
@@ -146577,6 +147128,15 @@ Task type definitions:
146577
147128
  - "chat": Conversations, questions, explanations, advice, discussions
146578
147129
  ${imageGenEnabled ? '- "image": Generate AI images and integrate them into the page' : ''}
146579
147130
 
147131
+ FALLBACK RULE:
147132
+ - If the request is vague, conversational, or doesn't clearly require code/image generation
147133
+ - If you're uncertain about how to categorize it
147134
+ - If it's a general question or discussion
147135
+ - If it seems like the user wants advice, help, or guidance
147136
+ → Create a single "chat" task with the original user message
147137
+
147138
+ CRITICAL: NEVER return an empty tasks array. When in doubt, use "chat".
147139
+
146580
147140
  CODE TASK RULES:
146581
147141
  - ALWAYS combine multiple code-related instructions into ONE code task
146582
147142
  - The AI can handle complex, multi-part code generation in a single task
@@ -146908,6 +147468,11 @@ ${isMixed ? 'CRITICAL: Only perform the task specified above. Do not answer othe
146908
147468
  // ====================================================================
146909
147469
  const system = `You are a helpful AI assistant for a web builder tool. You can answer questions about web development, design, HTML, CSS, JavaScript, and provide general assistance.
146910
147470
 
147471
+ When providing code examples:
147472
+ - Use markdown code blocks with language tags: \`\`\`html, \`\`\`css, \`\`\`javascript
147473
+ - Use inline code for short snippets: \`<element>\`
147474
+ - Never output raw HTML that could be rendered by the browser
147475
+
146911
147476
  ${isMixed ? `CRITICAL INSTRUCTION: You are handling ONE SPECIFIC TASK from a multi-part request.
146912
147477
 
146913
147478
  Your ONLY task is: ${task.description}
@@ -147282,6 +147847,28 @@ ${this.builder.html()}
147282
147847
  this.builder.uo.saveForUndo();
147283
147848
  }
147284
147849
 
147850
+ const parser = new DOMParser();
147851
+ const doc = parser.parseFromString(code, 'text/html');
147852
+ const containers = doc.querySelectorAll('div.is-container');
147853
+ containers.forEach(container => {
147854
+ container.classList.add('size-17', 'leading-17'); // add default font-size & line-height
147855
+ });
147856
+ const sections = doc.querySelectorAll('div.is-section');
147857
+ sections.forEach(section => {
147858
+ const box = section.querySelector('.is-box');
147859
+
147860
+ if (box) {
147861
+ // Splitted section
147862
+ if (box.querySelector('.is-overlay-bg')) {
147863
+ // add classes: box-autofit min-height-70
147864
+ box.classList.add('box-autofit', 'min-height-70');
147865
+ } else {
147866
+ // add classes: box-autofit
147867
+ box.classList.add('box-autofit');
147868
+ }
147869
+ }
147870
+ });
147871
+ code = doc.body.innerHTML;
147285
147872
  this.builder.loadHtml(code);
147286
147873
  }
147287
147874
 
@@ -147387,7 +147974,7 @@ ${this.builder.html()}
147387
147974
  banner.className = 'demo-banner';
147388
147975
  banner.innerHTML = `
147389
147976
  <div style="
147390
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
147977
+ background: linear-gradient(135deg, #527cff 0%, #5563db 100%);
147391
147978
  color: white;
147392
147979
  padding: 12px 16px;
147393
147980
  border-radius: 8px;
@@ -147835,11 +148422,13 @@ Classes: p-0, p-2, p-3, p-4, p-6, p-8, p-10, p-12
147835
148422
  **Example: Card with padding**
147836
148423
 
147837
148424
  <!-- Example: Card with padding -->
147838
- <div class="p-12 bg-gray-50">
148425
+ <div class="p-12 box-border bg-gray-50">
147839
148426
  <p class="size-18 pb-4">Card content</p>
147840
148427
  <p class="size-14 text-gray-600">Description</p>
147841
148428
  </div>
147842
148429
 
148430
+ **Key classes:** p-X, box-border (always use box-border with padding on DIV or cards)
148431
+
147843
148432
  ### Directional Padding
147844
148433
 
147845
148434
  Classes: px-4, py-4, pt-4, pb-4, pl-4, pr-4
@@ -147996,7 +148585,7 @@ border-2 border-solid mt-2 mb-1 font-normal tracking-normal rounded-full
147996
148585
  </a>
147997
148586
  </div>
147998
148587
 
147999
- **Key classes:** 'underline' + 'border-transparent' (no horizontal padding needed).
148588
+ **Key classes:** 'underline'+ 'underline-offset-4' + 'border-transparent' (no horizontal padding needed).
148000
148589
 
148001
148590
  **For button groups:**
148002
148591
 
@@ -148072,8 +148661,7 @@ Use grayscale for minimalist design.
148072
148661
  > **Editorial Style:** Stick to black, white, and grays for a clean, minimalist aesthetic. Use color sparingly for accents.
148073
148662
 
148074
148663
  ` + `
148075
-
148076
- ### Animation
148664
+ ## Animation
148077
148665
 
148078
148666
  **Transition**
148079
148667
 
@@ -148081,80 +148669,117 @@ Classes: transition-none, transition, transition-colors, transition-opacity, tra
148081
148669
 
148082
148670
  **Duration**
148083
148671
 
148084
- Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-500, duration-700, duration-1000, duration-1500
148672
+ Classes: duration-75, duration-100, duration-150, duration-200, duration-300, duration-400, duration-500, duration-600, duration-700, duration-800, duration-900, duration-1000, duration-1500
148085
148673
 
148086
148674
  **Timing**
148087
148675
 
148088
148676
  Classes: ease-linear, ease-in, ease-out, ease-in-out
148089
148677
 
148090
- **Delay**
148678
+ **Hover Transforms**
148091
148679
 
148092
- Classes: delay-75, delay-100, delay-150, delay-200, delay-300, delay-500
148680
+ Classes: hover:scale-105, hover:-translate-y-1, hover:-translate-y-2
148093
148681
 
148094
- **Scale**
148682
+ **Hover Shadow**
148095
148683
 
148096
- Classes: scale-0, scale-50, scale-75, scale-90, scale-95, scale-100, scale-105, scale-110, scale-125, scale-150
148684
+ Classes: hover:shadow-sm, hover:shadow, hover:shadow-md, hover:shadow-lg, hover:shadow-xl, hover:shadow-2xl
148097
148685
 
148098
- **Hover Effect**
148686
+ **Hover Background Colors**
148099
148687
 
148100
- Classes: hover:scale-105
148688
+ Classes: hover:bg-white, hover:bg-black, hover:bg-gray-50, hover:bg-gray-100, hover:bg-gray-200, hover:bg-gray-300, hover:bg-gray-400, hover:bg-gray-500, hover:bg-gray-600, hover:bg-gray-700, hover:bg-gray-800, hover:bg-gray-900, hover:bg-transparent
148101
148689
 
148102
- **Rotate**
148690
+ **Hover Text Colors**
148103
148691
 
148104
- Classes: rotate-0, rotate-45, rotate-90, rotate-180
148692
+ Classes: hover:text-white, hover:text-black, hover:text-current, hover:text-gray-50, hover:text-gray-100, hover:text-gray-200, hover:text-gray-300, hover:text-gray-400, hover:text-gray-500, hover:text-gray-600, hover:text-gray-700, hover:text-gray-800, hover:text-gray-900, hover:text-gray-950
148105
148693
 
148106
- **Translate X**
148694
+ **Hover Opacity**
148107
148695
 
148108
- Classes: translate-x-0, translate-x-1, translate-x-2, translate-x-4, translate-x-8
148696
+ Classes: hover:opacity-70, hover:opacity-75, hover:opacity-80, hover:opacity-90, hover:opacity-95, hover:opacity-100
148109
148697
 
148110
- **Translate Y**
148698
+ **Animation keyframes**
148699
+
148700
+ Classes: spin, ping, pulse, bounce
148111
148701
 
148112
- Classes: translate-y-0, translate-y-1, translate-y-2, translate-y-4, translate-y-8
148702
+ ### Animation Examples
148703
+
148704
+ **Example: Hover lift on Cards**
148705
+
148706
+ <div class="row" style="gap: 30px;">
148707
+ <div class="column">
148708
+ <!-- card -->
148709
+ <div class="p-10 box-border bg-white h-full transition-transform duration-300 hover:-translate-y-2" style="border: 1px solid #e0e0e0;">
148710
+ <div class="mb-6 text-gray-300"><i class="bi bi-star-fill"></i><i class="bi bi-star-fill"></i><i class="bi bi-star-fill"></i><i class="bi bi-star-fill"></i><i class="bi bi-star-fill"></i></div>
148711
+ <p class="size-18 leading-16 mb-8 text-gray-800">"It's rare to find a tool that balances power with simplicity so effectively. It has completely streamlined our workflow."</p>
148712
+ <p class="size-13 font-bold uppercase tracking-widest">Freja E. — Company</p>
148713
+ </div>
148714
+ </div>
148715
+ <div class="column">
148716
+ <!-- card -->
148717
+ </div>
148718
+ <div class="column">
148719
+ <!-- card -->
148720
+ </div>
148721
+ </div>
148113
148722
 
148114
- **Skew**
148723
+ **Key classes:** transition-transform, duration-300, hover:translate-y--2
148115
148724
 
148116
- Classes: skew-x-0, skew-x-3, skew-x-6, skew-y-0, skew-y-3, skew-y-6
148725
+ **Example: Hover lift and shadow on Cards**
148117
148726
 
148118
- **Overflow**
148727
+ <div class="row" style="gap: 30px;">
148728
+ <div class="column">
148729
+ <!-- card -->
148730
+ <div class="p-10 box-border bg-white transition-all duration-300 ease-out hover:-translate-y-2 hover:shadow-xl" style="border: 1px solid #e5e5e5;">
148731
+ <!-- card content -->
148732
+ </div>
148733
+ </div>
148734
+ <div class="column">
148735
+ <!-- card -->
148736
+ </div>
148737
+ <div class="column">
148738
+ <!-- card -->
148739
+ </div>
148740
+ </div>
148119
148741
 
148120
- Classes: overflow-hidden, overflow-visible, overflow-scroll, overflow-auto
148742
+ **Key classes:** transition-all duration-300 ease-out hover:-translate-y-2 hover:shadow-xl
148121
148743
 
148122
- **Opacity**
148744
+ **Example: Hover zoom on Cards**
148123
148745
 
148124
- Classes:
148746
+ <div class="row" style="gap: 30px;">
148747
+ <div class="column">
148748
+ <!-- card -->
148749
+ <div class="p-12 box-border bg-white h-full flex flex-col items-center text-center transition-transform duration-300 ease-out hover:scale-105" style="box-shadow: 0 10px 40px -10px rgba(0,0,0,0.05);">
148750
+ <!-- card content -->
148751
+ </div>
148752
+ </div>
148753
+ <div class="column">
148754
+ <!-- card -->
148755
+ </div>
148756
+ <div class="column">
148757
+ <!-- card -->
148758
+ </div>
148759
+ </div>
148125
148760
 
148126
- | Class | Color |
148127
- | ------------ | ------------- |
148128
- | '.opacity-0' | opacity: 0 |
148129
- | '.opacity-2' | opacity: 0.02 |
148130
- | '.opacity-4' | opacity: 0.04 |
148131
- | '.opacity-5' | opacity: 0.05 |
148132
- | '.opacity-6' | opacity: 0.06 |
148133
- | '.opacity-8' | opacity: 0.07 |
148134
- | '.opacity-10' | opacity: 0.1 |
148135
- | '.opacity-12' | opacity: 0.12 |
148136
- | '.opacity-15' | opacity: 0.15 |
148137
- | '.opacity-20' | opacity: 0.2 |
148138
- | '.opacity-25' | opacity: 0.25 |
148139
- | '.opacity-30' | opacity: 0.3 |
148140
- | '.opacity-35' | opacity: 0.35 |
148141
- | '.opacity-40' | opacity: 0.4 |
148142
- | '.opacity-45' | opacity: 0.45 |
148143
- | '.opacity-50' | opacity: 0.5 |
148144
- | '.opacity-55' | opacity: 0.55 |
148145
- | '.opacity-60' | opacity: 0.6 |
148146
- | '.opacity-65' | opacity: 0.65 |
148147
- | '.opacity-70' | opacity: 0.7 |
148148
- | '.opacity-75' | opacity: 0.75 |
148149
- | '.opacity-80' | opacity: 0.8 |
148150
- | '.opacity-85' | opacity: 0.85 |
148151
- | '.opacity-90' | opacity: 0.9 |
148152
- | '.opacity-95' | opacity: 0.95 |
148153
- | '.opacity-100' | opacity: 1 |
148761
+ **Key classes:** transition-transform, duration-300, ease-out, hover:scale-105
148154
148762
 
148155
- **Animation keyframes**
148763
+ **Example: Hover zoom on Images**
148156
148764
 
148157
- Classes: spin, ping, pulse, bounce
148765
+ <div class="row" style="gap:40px;">
148766
+ <div class="column">
148767
+ <div class="w-full overflow-hidden relative bg-gray-50 mb-6" style="aspect-ratio: 4 / 3;">
148768
+ <img src="image1.jpg" alt="Freja E. Andersen" class="w-full h-full object-cover transition-transform hover:scale-105 duration-1000">
148769
+ </div>
148770
+ <h4 class="size-20 font-normal">Freja E. Andersen</h4>
148771
+ <p class="size-14 text-gray-500 uppercase tracking-wide mt-1 mb-3">Lead Architect</p>
148772
+ <p class="size-15 text-gray-600 leading-16">Specializing in sustainable residential architecture with a focus on natural light.</p>
148773
+ </div>
148774
+ <div class="column">
148775
+
148776
+ </div>
148777
+ <div class="column">
148778
+
148779
+ </div>
148780
+ </div>
148781
+
148782
+ **Key classes:** transition-transform, hover:scale-105, duration-1000 (or use duration-1500 for larger image)
148158
148783
  ` + `
148159
148784
  ---
148160
148785
  ` + `
@@ -148177,7 +148802,7 @@ Classes: spin, ping, pulse, bounce
148177
148802
 
148178
148803
  ### Card with Padding
148179
148804
 
148180
- <div class="p-12 bg-gray-50">
148805
+ <div class="p-12 box-border bg-gray-50">
148181
148806
  <p class="size-18 leading-17 text-black pb-4">
148182
148807
  Card title or content
148183
148808
  </p>
@@ -148224,16 +148849,18 @@ Classes: spin, ping, pulse, bounce
148224
148849
  </div>
148225
148850
  <div class="row">
148226
148851
  <div class="column">
148227
- <img class="pb-2" src="https://placehold.co/400x400/f5f5f5/999?text=Alex+T" alt="Team Member">
148852
+ <div class="w-full overflow-hidden relative bg-gray-50 mb-2" style="aspect-ratio: 4 / 3;">
148853
+ <img src="image1.jpg" alt="Freja E. Andersen" class="w-full h-full object-cover transition-transform hover:scale-105 duration-1000">
148854
+ </div>
148228
148855
  <h4 class="size-18 font-medium pb-2 text-center">Alex Thompson</h4>
148229
148856
  <p class="size-12 uppercase tracking-150 text-gray-500 pb-3 text-center">Founder &amp; CEO</p>
148230
148857
  <p class="size-15 leading-16 text-gray-600 text-center">Visionary leader with 15 years of experience.</p>
148231
148858
  </div>
148232
148859
  <div class="column">
148233
- <img class="pb-2" src="https://placehold.co/400x400/f5f5f5/999?text=Sophia+M" alt="Team Member">
148234
- <h4 class="size-18 font-medium pb-2 text-center">Sophia Martinez</h4>
148235
- <p class="size-12 uppercase tracking-150 text-gray-500 pb-3 text-center">CTO</p>
148236
- <p class="size-15 leading-16 text-gray-600 text-center">Technical architect building systems.</p>
148860
+ <!-- Next image -->
148861
+ </div>
148862
+ <div class="column">
148863
+ <!-- Next image -->
148237
148864
  </div>
148238
148865
  </div>
148239
148866
 
@@ -148586,23 +149213,15 @@ The overlay system provides background images and colors behind content.
148586
149213
  </div>
148587
149214
  </div>
148588
149215
 
148589
- ### Background Image with Color Overlay
148590
-
148591
- <div class="is-overlay" style="background-color: rgb(225, 225, 225);">
148592
- <div class="is-overlay-bg"
148593
- style="background-image: url('image.jpg');
148594
- background-position: 50% 60%;
148595
- opacity: 0.7;">
148596
- </div>
148597
- </div>
148598
-
148599
149216
  ### Dark Overlay on Image
148600
149217
 
149218
+ **Use case:** For the background behind white text content.
149219
+
148601
149220
  <div class="is-overlay">
148602
149221
  <div class="is-overlay-bg"
148603
149222
  style="background-image: url('image.jpg');
148604
149223
  background-position: 50% 60%;">
148605
- <div class="is-overlay-color opacity-12"></div>
149224
+ <div class="is-overlay-color opacity-30"></div>
148606
149225
  </div>
148607
149226
  </div>
148608
149227
 
@@ -148707,7 +149326,6 @@ Add internal spacing inside containers:
148707
149326
 
148708
149327
  **Padding classes:**
148709
149328
 
148710
- - 'content-py-*' - Vertical padding (top and bottom)
148711
149329
  - 'content-pt-*' - Top padding only
148712
149330
  - 'content-pb-*' - Bottom padding only
148713
149331
 
@@ -148946,6 +149564,24 @@ The Box Framework provides structure. The Content.css Framework provides content
148946
149564
 
148947
149565
  Always use both frameworks together for complete designs.
148948
149566
 
149567
+ ### 9. Add smooth image scaling for overlay background image
149568
+
149569
+ <div class="is-section ...">
149570
+ <!-- Section content -->
149571
+ </div>
149572
+ <div class="is-section ...">
149573
+ <!-- Section content -->
149574
+ </div>
149575
+ <style>
149576
+ /* Smooth image scaling */
149577
+ .is-overlay-bg {
149578
+ transition: transform 1.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
149579
+ }
149580
+ .is-box:hover .is-overlay-bg {
149581
+ transform: scale(1.03);
149582
+ }
149583
+ </style>
149584
+
148949
149585
  ---
148950
149586
 
148951
149587
  ## Common Patterns
@@ -148985,6 +149621,29 @@ Always use both frameworks together for complete designs.
148985
149621
  </div>
148986
149622
  </div>
148987
149623
 
149624
+ ### Pattern: Dark overlay background image behind white text content.
149625
+
149626
+ <div class="is-section is-box type-system-ui is-section-60 is-content-bottom edge-y-4">
149627
+ <div class="is-overlay">
149628
+ <div class="is-overlay-bg" style="background-image: url('assets/thelayout/images/ai-aZkV0.jpg'); background-position: 50% 40%;">
149629
+ <div class="is-overlay-color opacity-30"></div>
149630
+ </div>
149631
+ </div>
149632
+ <div class="is-container is-content-1200 text-center">
149633
+ <div class="row">
149634
+ <div class="column">
149635
+ <h2 class="size-60 font-light text-white leading-12 pb-6">Start your next chapter.</h2>
149636
+ <div class="spacer height-20"></div>
149637
+ <div>
149638
+ <a href="#" role="button" class="transition-all inline-block whitespace-nowrap cursor-pointer no-underline border-2 border-solid mt-2 mb-1 font-normal tracking-normal rounded-full py-3 px-10 size-16 leading-16 border-white hover:bg-white hover:text-black" style="color: #ffffff;">
149639
+ Visit Us Today
149640
+ </a>
149641
+ </div>
149642
+ </div>
149643
+ </div>
149644
+ </div>
149645
+ </div>
149646
+
148988
149647
  ### Pattern: Three Equal Boxes
148989
149648
 
148990
149649
  <div class="is-section type-system-ui is-section-60">
@@ -149288,14 +149947,16 @@ The frameworks provide utility classes for structure and typography. To create r
149288
149947
 
149289
149948
  <!-- Embedded Styke -->
149290
149949
  <style>
149291
- /* Subtle hover zoom for background images */
149292
- .is-overlay-bg {
149293
- transition: transform 1s ease;
149294
- }
149295
- .is-box:hover .is-overlay-bg {
149296
- transform: scale(1.05);
149297
- }
149950
+ `
149951
+ /* Subtle hover zoom for background images
149952
+ .is-overlay-bg {
149953
+ transition: transform 1.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
149954
+ }
149298
149955
 
149956
+ .is-box:hover .is-overlay-bg {
149957
+ transform: scale(1.03);
149958
+ }*/
149959
+ + `
149299
149960
  /* Featured image */
149300
149961
  .featured-image {
149301
149962
  width: 100%;