@innovastudio/contentbox 1.6.179 → 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
@@ -146554,12 +147094,16 @@ OUT OF SCOPE requests include:
146554
147094
  ${imageGenEnabled ? '' : '- AI image generation (currently disabled - but external images are OK)'}
146555
147095
 
146556
147096
  IMPORTANT DISTINCTION:
146557
- - "Tell me about the weather in general" → VALID (chat/education)
146558
147097
  - "What's the weather in Tokyo right now?" → INVALID (requires real-time data)
146559
- - "Write a story about space" → VALID (chat/creative)
147098
+ - "Tell me about the weather in general" → VALID (chat task)
146560
147099
  - "Generate a video about space" → INVALID (video generation)
146561
- - "Explain how databases work" → VALID (chat/education)
147100
+ - "Write a story about space" → VALID (chat task)
146562
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.
146563
147107
 
146564
147108
  Respond with a JSON object in this exact format:
146565
147109
  {
@@ -146584,6 +147128,15 @@ Task type definitions:
146584
147128
  - "chat": Conversations, questions, explanations, advice, discussions
146585
147129
  ${imageGenEnabled ? '- "image": Generate AI images and integrate them into the page' : ''}
146586
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
+
146587
147140
  CODE TASK RULES:
146588
147141
  - ALWAYS combine multiple code-related instructions into ONE code task
146589
147142
  - The AI can handle complex, multi-part code generation in a single task
@@ -146915,6 +147468,11 @@ ${isMixed ? 'CRITICAL: Only perform the task specified above. Do not answer othe
146915
147468
  // ====================================================================
146916
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.
146917
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
+
146918
147476
  ${isMixed ? `CRITICAL INSTRUCTION: You are handling ONE SPECIFIC TASK from a multi-part request.
146919
147477
 
146920
147478
  Your ONLY task is: ${task.description}
@@ -147289,6 +147847,28 @@ ${this.builder.html()}
147289
147847
  this.builder.uo.saveForUndo();
147290
147848
  }
147291
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;
147292
147872
  this.builder.loadHtml(code);
147293
147873
  }
147294
147874
 
@@ -147842,11 +148422,13 @@ Classes: p-0, p-2, p-3, p-4, p-6, p-8, p-10, p-12
147842
148422
  **Example: Card with padding**
147843
148423
 
147844
148424
  <!-- Example: Card with padding -->
147845
- <div class="p-12 bg-gray-50">
148425
+ <div class="p-12 box-border bg-gray-50">
147846
148426
  <p class="size-18 pb-4">Card content</p>
147847
148427
  <p class="size-14 text-gray-600">Description</p>
147848
148428
  </div>
147849
148429
 
148430
+ **Key classes:** p-X, box-border (always use box-border with padding on DIV or cards)
148431
+
147850
148432
  ### Directional Padding
147851
148433
 
147852
148434
  Classes: px-4, py-4, pt-4, pb-4, pl-4, pr-4
@@ -148003,7 +148585,7 @@ border-2 border-solid mt-2 mb-1 font-normal tracking-normal rounded-full
148003
148585
  </a>
148004
148586
  </div>
148005
148587
 
148006
- **Key classes:** 'underline' + 'border-transparent' (no horizontal padding needed).
148588
+ **Key classes:** 'underline'+ 'underline-offset-4' + 'border-transparent' (no horizontal padding needed).
148007
148589
 
148008
148590
  **For button groups:**
148009
148591
 
@@ -148079,8 +148661,7 @@ Use grayscale for minimalist design.
148079
148661
  > **Editorial Style:** Stick to black, white, and grays for a clean, minimalist aesthetic. Use color sparingly for accents.
148080
148662
 
148081
148663
  ` + `
148082
-
148083
- ### Animation
148664
+ ## Animation
148084
148665
 
148085
148666
  **Transition**
148086
148667
 
@@ -148088,80 +148669,117 @@ Classes: transition-none, transition, transition-colors, transition-opacity, tra
148088
148669
 
148089
148670
  **Duration**
148090
148671
 
148091
- 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
148092
148673
 
148093
148674
  **Timing**
148094
148675
 
148095
148676
  Classes: ease-linear, ease-in, ease-out, ease-in-out
148096
148677
 
148097
- **Delay**
148678
+ **Hover Transforms**
148098
148679
 
148099
- 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
148100
148681
 
148101
- **Scale**
148682
+ **Hover Shadow**
148102
148683
 
148103
- 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
148104
148685
 
148105
- **Hover Effect**
148686
+ **Hover Background Colors**
148106
148687
 
148107
- 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
148108
148689
 
148109
- **Rotate**
148690
+ **Hover Text Colors**
148110
148691
 
148111
- 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
148112
148693
 
148113
- **Translate X**
148694
+ **Hover Opacity**
148114
148695
 
148115
- 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
148116
148697
 
148117
- **Translate Y**
148698
+ **Animation keyframes**
148118
148699
 
148119
- Classes: translate-y-0, translate-y-1, translate-y-2, translate-y-4, translate-y-8
148700
+ Classes: spin, ping, pulse, bounce
148701
+
148702
+ ### Animation Examples
148120
148703
 
148121
- **Skew**
148704
+ **Example: Hover lift on Cards**
148122
148705
 
148123
- Classes: skew-x-0, skew-x-3, skew-x-6, skew-y-0, skew-y-3, skew-y-6
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>
148722
+
148723
+ **Key classes:** transition-transform, duration-300, hover:translate-y--2
148724
+
148725
+ **Example: Hover lift and shadow on Cards**
148726
+
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>
148124
148741
 
148125
- **Overflow**
148742
+ **Key classes:** transition-all duration-300 ease-out hover:-translate-y-2 hover:shadow-xl
148126
148743
 
148127
- Classes: overflow-hidden, overflow-visible, overflow-scroll, overflow-auto
148744
+ **Example: Hover zoom on Cards**
148128
148745
 
148129
- **Opacity**
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>
148130
148760
 
148131
- Classes:
148761
+ **Key classes:** transition-transform, duration-300, ease-out, hover:scale-105
148132
148762
 
148133
- | Class | Color |
148134
- | ------------ | ------------- |
148135
- | '.opacity-0' | opacity: 0 |
148136
- | '.opacity-2' | opacity: 0.02 |
148137
- | '.opacity-4' | opacity: 0.04 |
148138
- | '.opacity-5' | opacity: 0.05 |
148139
- | '.opacity-6' | opacity: 0.06 |
148140
- | '.opacity-8' | opacity: 0.07 |
148141
- | '.opacity-10' | opacity: 0.1 |
148142
- | '.opacity-12' | opacity: 0.12 |
148143
- | '.opacity-15' | opacity: 0.15 |
148144
- | '.opacity-20' | opacity: 0.2 |
148145
- | '.opacity-25' | opacity: 0.25 |
148146
- | '.opacity-30' | opacity: 0.3 |
148147
- | '.opacity-35' | opacity: 0.35 |
148148
- | '.opacity-40' | opacity: 0.4 |
148149
- | '.opacity-45' | opacity: 0.45 |
148150
- | '.opacity-50' | opacity: 0.5 |
148151
- | '.opacity-55' | opacity: 0.55 |
148152
- | '.opacity-60' | opacity: 0.6 |
148153
- | '.opacity-65' | opacity: 0.65 |
148154
- | '.opacity-70' | opacity: 0.7 |
148155
- | '.opacity-75' | opacity: 0.75 |
148156
- | '.opacity-80' | opacity: 0.8 |
148157
- | '.opacity-85' | opacity: 0.85 |
148158
- | '.opacity-90' | opacity: 0.9 |
148159
- | '.opacity-95' | opacity: 0.95 |
148160
- | '.opacity-100' | opacity: 1 |
148763
+ **Example: Hover zoom on Images**
148161
148764
 
148162
- **Animation keyframes**
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>
148163
148781
 
148164
- Classes: spin, ping, pulse, bounce
148782
+ **Key classes:** transition-transform, hover:scale-105, duration-1000 (or use duration-1500 for larger image)
148165
148783
  ` + `
148166
148784
  ---
148167
148785
  ` + `
@@ -148184,7 +148802,7 @@ Classes: spin, ping, pulse, bounce
148184
148802
 
148185
148803
  ### Card with Padding
148186
148804
 
148187
- <div class="p-12 bg-gray-50">
148805
+ <div class="p-12 box-border bg-gray-50">
148188
148806
  <p class="size-18 leading-17 text-black pb-4">
148189
148807
  Card title or content
148190
148808
  </p>
@@ -148231,16 +148849,18 @@ Classes: spin, ping, pulse, bounce
148231
148849
  </div>
148232
148850
  <div class="row">
148233
148851
  <div class="column">
148234
- <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>
148235
148855
  <h4 class="size-18 font-medium pb-2 text-center">Alex Thompson</h4>
148236
148856
  <p class="size-12 uppercase tracking-150 text-gray-500 pb-3 text-center">Founder &amp; CEO</p>
148237
148857
  <p class="size-15 leading-16 text-gray-600 text-center">Visionary leader with 15 years of experience.</p>
148238
148858
  </div>
148239
148859
  <div class="column">
148240
- <img class="pb-2" src="https://placehold.co/400x400/f5f5f5/999?text=Sophia+M" alt="Team Member">
148241
- <h4 class="size-18 font-medium pb-2 text-center">Sophia Martinez</h4>
148242
- <p class="size-12 uppercase tracking-150 text-gray-500 pb-3 text-center">CTO</p>
148243
- <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 -->
148244
148864
  </div>
148245
148865
  </div>
148246
148866
 
@@ -148706,7 +149326,6 @@ Add internal spacing inside containers:
148706
149326
 
148707
149327
  **Padding classes:**
148708
149328
 
148709
- - 'content-py-*' - Vertical padding (top and bottom)
148710
149329
  - 'content-pt-*' - Top padding only
148711
149330
  - 'content-pb-*' - Bottom padding only
148712
149331
 
@@ -149328,23 +149947,16 @@ The frameworks provide utility classes for structure and typography. To create r
149328
149947
 
149329
149948
  <!-- Embedded Styke -->
149330
149949
  <style>
149331
- /* Smooth image scaling */
149332
- .is-overlay-bg {
149333
- transition: transform 1.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
149334
- }
149335
-
149336
- .is-box:hover .is-overlay-bg {
149337
- transform: scale(1.03);
149338
- }
149339
-
149340
- /* Subtle hover zoom for background images */
149341
- .is-overlay-bg {
149342
- transition: transform 1s ease;
149343
- }
149344
- .is-box:hover .is-overlay-bg {
149345
- transform: scale(1.05);
149346
- }
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
+ }
149347
149955
 
149956
+ .is-box:hover .is-overlay-bg {
149957
+ transform: scale(1.03);
149958
+ }*/
149959
+ + `
149348
149960
  /* Featured image */
149349
149961
  .featured-image {
149350
149962
  width: 100%;