Changeset 3472405
- Timestamp:
- 03/02/2026 07:27:20 AM (5 weeks ago)
- Location:
- frontblocks
- Files:
-
- 2 added
- 24 edited
- 1 copied
-
tags/1.3.3 (copied) (copied from frontblocks/trunk)
-
tags/1.3.3/assets/admin/settings.css (modified) (21 diffs)
-
tags/1.3.3/assets/carousel/frontblocks-advanced-option.js (modified) (9 diffs)
-
tags/1.3.3/assets/carousel/frontblocks-carousel-editor.css (added)
-
tags/1.3.3/assets/carousel/frontblocks-carousel.css (modified) (5 diffs)
-
tags/1.3.3/assets/carousel/frontblocks-carousel.js (modified) (6 diffs)
-
tags/1.3.3/assets/gravityforms-inline/frontblocks-gf-inline.css (modified) (1 diff)
-
tags/1.3.3/assets/shape-animations/frontblocks-shape-animation-option.js (modified) (7 diffs)
-
tags/1.3.3/assets/stacked-images/frontblocks-stacked-images-frontend.js (modified) (2 diffs)
-
tags/1.3.3/assets/stacked-images/frontblocks-stacked-images.css (modified) (5 diffs)
-
tags/1.3.3/frontblocks.php (modified) (2 diffs)
-
tags/1.3.3/includes/Frontend/Carousel.php (modified) (9 diffs)
-
tags/1.3.3/readme.txt (modified) (2 diffs)
-
tags/1.3.3/vendor/composer/installed.php (modified) (2 diffs)
-
trunk/assets/admin/settings.css (modified) (21 diffs)
-
trunk/assets/carousel/frontblocks-advanced-option.js (modified) (9 diffs)
-
trunk/assets/carousel/frontblocks-carousel-editor.css (added)
-
trunk/assets/carousel/frontblocks-carousel.css (modified) (5 diffs)
-
trunk/assets/carousel/frontblocks-carousel.js (modified) (6 diffs)
-
trunk/assets/gravityforms-inline/frontblocks-gf-inline.css (modified) (1 diff)
-
trunk/assets/shape-animations/frontblocks-shape-animation-option.js (modified) (7 diffs)
-
trunk/assets/stacked-images/frontblocks-stacked-images-frontend.js (modified) (2 diffs)
-
trunk/assets/stacked-images/frontblocks-stacked-images.css (modified) (5 diffs)
-
trunk/frontblocks.php (modified) (2 diffs)
-
trunk/includes/Frontend/Carousel.php (modified) (9 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/vendor/composer/installed.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
frontblocks/tags/1.3.3/assets/admin/settings.css
r3462660 r3472405 521 521 margin-left: -0.25rem; 522 522 } 523 .frbl-settings-wrapper .tw-mb-0 { 524 margin-bottom: 0px; 525 } 523 526 .frbl-settings-wrapper .tw-mb-2 { 524 527 margin-bottom: 0.5rem; … … 530 533 margin-bottom: 2rem; 531 534 } 532 .frbl-settings-wrapper .tw-ml-2 {533 margin-left: 0.5rem;534 }535 535 .frbl-settings-wrapper .tw-ml-3 { 536 536 margin-left: 0.75rem; 537 537 } 538 .frbl-settings-wrapper .tw-ml-auto {539 margin-left: auto;540 }541 538 .frbl-settings-wrapper .tw-mr-2 { 542 539 margin-right: 0.5rem; 543 540 } 544 .frbl-settings-wrapper .tw-mt- 1{545 margin-top: 0 .25rem;541 .frbl-settings-wrapper .tw-mt-0 { 542 margin-top: 0px; 546 543 } 547 544 .frbl-settings-wrapper .tw-mt-2 { 548 545 margin-top: 0.5rem; 549 546 } 547 .frbl-settings-wrapper .tw-mt-4 { 548 margin-top: 1rem; 549 } 550 .frbl-settings-wrapper .tw-mt-6 { 551 margin-top: 1.5rem; 552 } 550 553 .frbl-settings-wrapper .tw-mt-8 { 551 554 margin-top: 2rem; … … 575 578 max-width: 64rem; 576 579 } 580 .frbl-settings-wrapper .tw-flex-1 { 581 flex: 1 1 0%; 582 } 577 583 .frbl-settings-wrapper .tw-flex-shrink-0 { 578 584 flex-shrink: 0; 579 585 } 580 .frbl-settings-wrapper .tw-flex-grow {581 flex-grow: 1;582 }583 .frbl-settings-wrapper .tw-items-start {584 align-items: flex-start;585 }586 586 .frbl-settings-wrapper .tw-items-center { 587 587 align-items: center; … … 592 592 .frbl-settings-wrapper .tw-gap-2 { 593 593 gap: 0.5rem; 594 }595 .frbl-settings-wrapper .tw-gap-3 {596 gap: 0.75rem;597 594 } 598 595 .frbl-settings-wrapper :is(.tw-space-x-2 > :not([hidden]) ~ :not([hidden])) { … … 601 598 margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); 602 599 } 603 .frbl-settings-wrapper :is(.tw-space-y-4 > :not([hidden]) ~ :not([hidden])) {604 --tw-space-y-reverse: 0;605 margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));606 margin-bottom: calc(1rem * var(--tw-space-y-reverse));607 }608 600 .frbl-settings-wrapper :is(.tw-space-y-6 > :not([hidden]) ~ :not([hidden])) { 609 601 --tw-space-y-reverse: 0; … … 611 603 margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); 612 604 } 605 .frbl-settings-wrapper .tw-overflow-auto { 606 overflow: auto; 607 } 613 608 .frbl-settings-wrapper .tw-overflow-hidden { 614 609 overflow: hidden; … … 647 642 border-color: rgb(209 213 219 / var(--tw-border-opacity, 1)); 648 643 } 649 .frbl-settings-wrapper .tw-border-green-300 {650 --tw-border-opacity: 1;651 border-color: rgb(134 239 172 / var(--tw-border-opacity, 1));652 }653 644 .frbl-settings-wrapper .tw-border-red-200 { 654 645 --tw-border-opacity: 1; 655 646 border-color: rgb(254 202 202 / var(--tw-border-opacity, 1)); 656 647 } 657 .frbl-settings-wrapper .tw-border-red-300 {658 --tw-border-opacity: 1;659 border-color: rgb(252 165 165 / var(--tw-border-opacity, 1));660 }661 648 .frbl-settings-wrapper .tw-border-transparent { 662 649 border-color: transparent; 663 650 } 664 .frbl-settings-wrapper .tw-border-yellow- 300 {651 .frbl-settings-wrapper .tw-border-yellow-200 { 665 652 --tw-border-opacity: 1; 666 border-color: rgb(25 3 224 71/ var(--tw-border-opacity, 1));653 border-color: rgb(254 240 138 / var(--tw-border-opacity, 1)); 667 654 } 668 655 .frbl-settings-wrapper .tw-border-yellow-400 { … … 678 665 background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1)); 679 666 } 680 .frbl-settings-wrapper .tw-bg-green-100 {681 --tw-bg-opacity: 1;682 background-color: rgb(220 252 231 / var(--tw-bg-opacity, 1));683 }684 667 .frbl-settings-wrapper .tw-bg-primary-100 { 685 668 --tw-bg-opacity: 1; … … 690 673 background-color: rgb(104 125 249 / var(--tw-bg-opacity, 1)); 691 674 } 692 .frbl-settings-wrapper .tw-bg-red-100 {693 --tw-bg-opacity: 1;694 background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1));695 }696 675 .frbl-settings-wrapper .tw-bg-red-50 { 697 676 --tw-bg-opacity: 1; … … 701 680 --tw-bg-opacity: 1; 702 681 background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); 703 }704 .frbl-settings-wrapper .tw-bg-yellow-100 {705 --tw-bg-opacity: 1;706 background-color: rgb(254 249 195 / var(--tw-bg-opacity, 1));707 682 } 708 683 .frbl-settings-wrapper .tw-bg-yellow-50 { … … 721 696 --tw-gradient-to: #fff var(--tw-gradient-to-position); 722 697 } 723 .frbl-settings-wrapper .tw-p-3 {724 padding: 0.75rem;725 }726 698 .frbl-settings-wrapper .tw-p-4 { 727 699 padding: 1rem; 700 } 701 .frbl-settings-wrapper .tw-p-6 { 702 padding: 1.5rem; 728 703 } 729 704 .frbl-settings-wrapper .tw-px-3 { … … 743 718 padding-bottom: 0.25rem; 744 719 } 720 .frbl-settings-wrapper .tw-py-2 { 721 padding-top: 0.5rem; 722 padding-bottom: 0.5rem; 723 } 745 724 .frbl-settings-wrapper .tw-py-3 { 746 725 padding-top: 0.75rem; … … 755 734 padding-bottom: 2rem; 756 735 } 757 .frbl-settings-wrapper .tw-pr-4 {758 padding-right: 1rem;759 }760 736 .frbl-settings-wrapper .tw-pt-6 { 761 737 padding-top: 1.5rem; … … 763 739 .frbl-settings-wrapper .tw-text-center { 764 740 text-align: center; 741 } 742 .frbl-settings-wrapper .tw-text-2xl { 743 font-size: 1.5rem; 744 line-height: 2rem; 765 745 } 766 746 .frbl-settings-wrapper .tw-text-3xl { … … 772 752 line-height: 1.5rem; 773 753 } 754 .frbl-settings-wrapper .tw-text-lg { 755 font-size: 1.125rem; 756 line-height: 1.75rem; 757 } 774 758 .frbl-settings-wrapper .tw-text-sm { 775 759 font-size: 0.875rem; … … 809 793 color: rgb(75 85 99 / var(--tw-text-opacity, 1)); 810 794 } 795 .frbl-settings-wrapper .tw-text-gray-700 { 796 --tw-text-opacity: 1; 797 color: rgb(55 65 81 / var(--tw-text-opacity, 1)); 798 } 811 799 .frbl-settings-wrapper .tw-text-gray-900 { 812 800 --tw-text-opacity: 1; 813 801 color: rgb(17 24 39 / var(--tw-text-opacity, 1)); 814 802 } 815 .frbl-settings-wrapper .tw-text-green-800 {816 --tw-text-opacity: 1;817 color: rgb(22 101 52 / var(--tw-text-opacity, 1));818 }819 803 .frbl-settings-wrapper .tw-text-primary-500 { 820 804 --tw-text-opacity: 1; … … 829 813 color: rgb(185 28 28 / var(--tw-text-opacity, 1)); 830 814 } 831 .frbl-settings-wrapper .tw-text-red-800 {832 --tw-text-opacity: 1;833 color: rgb(153 27 27 / var(--tw-text-opacity, 1));834 }835 815 .frbl-settings-wrapper .tw-text-white { 836 816 --tw-text-opacity: 1; … … 844 824 --tw-text-opacity: 1; 845 825 color: rgb(161 98 7 / var(--tw-text-opacity, 1)); 846 }847 .frbl-settings-wrapper .tw-text-yellow-800 {848 --tw-text-opacity: 1;849 color: rgb(133 77 14 / var(--tw-text-opacity, 1));850 826 } 851 827 .frbl-settings-wrapper .tw-underline { 852 828 text-decoration-line: underline; 853 }854 .frbl-settings-wrapper .tw-no-underline {855 text-decoration-line: none;856 }857 .frbl-settings-wrapper .tw-opacity-50 {858 opacity: 0.5;859 829 } 860 830 .frbl-settings-wrapper .tw-shadow-sm { … … 1052 1022 } 1053 1023 } 1054 .frbl-settings-wrapper .hover\:tw-bg-primary-200:hover {1055 --tw-bg-opacity: 1;1056 background-color: rgb(205 208 251 / var(--tw-bg-opacity, 1));1057 }1058 1024 .frbl-settings-wrapper .hover\:tw-bg-primary-600:hover { 1059 1025 --tw-bg-opacity: 1; … … 1063 1029 --tw-text-opacity: 1; 1064 1030 color: rgb(85 101 237 / var(--tw-text-opacity, 1)); 1065 }1066 .frbl-settings-wrapper .hover\:tw-no-underline:hover {1067 text-decoration-line: none;1068 1031 } 1069 1032 .frbl-settings-wrapper .focus\:tw-border-transparent:focus { … … 1101 1064 } 1102 1065 1103 /* Custom styles for license fields */1104 .frbl-settings-wrapper .tw-text-base:not(button) {1105 font-size: 1rem;1106 line-height: 1.5rem;1107 width: 100%;1108 }1109 1110 .frbl-settings-wrapper .tw-flex {1111 display: flex;1112 column-gap: 20px;1113 }1114 1115 /* Submit button width */1116 .frbl-settings-wrapper .tw-w-1\/2 {1117 width: 50%;1118 }1119 1120 /* Features Grid Layout */1121 .frbl-section-wrapper {1122 margin-bottom: 3rem;1123 }1124 1125 .frbl-features-grid {1126 display: grid;1127 grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));1128 gap: 1.25rem;1129 }1130 1131 /* Feature Card Styles */1132 .frbl-feature-card {1133 position: relative;1134 background: #ffffff;1135 border: 1px solid #e5e7eb;1136 border-radius: 12px;1137 padding: 1.5rem;1138 transition: all 0.2s ease;1139 overflow: hidden;1140 display: flex;1141 flex-direction: column;1142 min-height: 80px;1143 }1144 1145 .frbl-feature-card:hover {1146 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);1147 transform: translateY(-2px);1148 border-color: #687df9;1149 }1150 1151 /* PRO Badge */1152 .frbl-pro-badge {1153 position: absolute;1154 top: 0;1155 left: 0;1156 background: linear-gradient(135deg, #ec4899 0%, #f97316 100%);1157 color: #ffffff;1158 font-size: 0.625rem;1159 font-weight: 700;1160 letter-spacing: 0.05em;1161 padding: 0.25rem 0.75rem;1162 border-radius: 0 0 12px 0;1163 box-shadow: 0 2px 4px rgba(236, 72, 153, 0.3);1164 z-index: 10;1165 }1166 1167 /* Feature Card Content */1168 .frbl-feature-content {1169 display: flex;1170 align-items: center;1171 justify-content: space-between;1172 gap: 1rem;1173 min-height: 3rem;1174 }1175 1176 /* Feature Icon */1177 .frbl-feature-icon {1178 flex-shrink: 0;1179 width: 2.5rem;1180 height: 2.5rem;1181 display: flex;1182 align-items: center;1183 justify-content: center;1184 background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);1185 border-radius: 10px;1186 color: #687df9;1187 transition: all 0.2s ease;1188 }1189 1190 .frbl-feature-card:hover .frbl-feature-icon {1191 background: linear-gradient(135deg, #e0e3fc 0%, #d0d4fb 100%);1192 transform: scale(1.05);1193 }1194 1195 .frbl-feature-icon svg {1196 width: 1.5rem;1197 height: 1.5rem;1198 stroke-width: 2;1199 }1200 1201 /* Feature Info */1202 .frbl-feature-info {1203 flex: 1;1204 min-width: 0;1205 display: flex;1206 align-items: center;1207 }1208 1209 .frbl-feature-title {1210 font-size: 0.9375rem;1211 font-weight: 600;1212 color: #1f2937;1213 margin: 0;1214 line-height: 1.5;1215 }1216 1217 .frbl-feature-description {1218 font-size: 0.8125rem;1219 color: #6b7280;1220 margin: 0.25rem 0 0 0;1221 line-height: 1.4;1222 }1223 1224 /* Active Feature Cards */1225 .frbl-feature-card.frbl-feature-active {1226 background: linear-gradient(135deg, #ffffff 0%, #f0fdf4 100%);1227 border-color: #d1fae5;1228 }1229 1230 .frbl-feature-card.frbl-feature-active:hover {1231 border-color: #10b981;1232 }1233 1234 .frbl-feature-card.frbl-feature-active .frbl-feature-icon {1235 background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);1236 color: #10b981;1237 }1238 1239 .frbl-feature-card.frbl-feature-active:hover .frbl-feature-icon {1240 background: linear-gradient(135deg, #a7f3d0 0%, #6ee7b7 100%);1241 }1242 1243 /* Active cards need vertical layout for description */1244 .frbl-feature-card.frbl-feature-active .frbl-feature-info {1245 flex-direction: column;1246 align-items: flex-start;1247 }1248 1249 /* Active cards don't have toggle, so don't use space-between */1250 .frbl-feature-card.frbl-feature-active .frbl-feature-content {1251 justify-content: flex-start;1252 }1253 1254 /* Feature Toggle */1255 .frbl-feature-toggle {1256 flex-shrink: 0;1257 display: flex;1258 align-items: center;1259 }1260 1261 /* PRO Card Styles */1262 .frbl-feature-card.frbl-feature-pro {1263 background: linear-gradient(135deg, #ffffff 0%, #fef3f2 100%);1264 border-color: #fee2e2;1265 }1266 1267 .frbl-feature-card.frbl-feature-pro:hover {1268 border-color: #ec4899;1269 }1270 1271 .frbl-feature-card.frbl-feature-pro .frbl-feature-icon {1272 background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);1273 color: #ec4899;1274 }1275 1276 .frbl-feature-card.frbl-feature-pro:hover .frbl-feature-icon {1277 background: linear-gradient(135deg, #fecaca 0%, #fca5a5 100%);1278 }1279 1280 /* Disabled state for PRO features without license */1281 .frbl-feature-card.frbl-feature-pro .frbl-toggle:has(input:disabled) {1282 opacity: 0.6;1283 }1284 1285 /* Responsive adjustments */1286 @media (max-width: 768px) {1287 .frbl-features-grid {1288 grid-template-columns: 1fr;1289 }1290 1291 .frbl-feature-card {1292 padding: 1.25rem;1293 }1294 }1295 1296 @media (min-width: 768px) and (max-width: 1024px) {1297 .frbl-features-grid {1298 grid-template-columns: repeat(2, 1fr);1299 }1300 }1301 1302 1303 /* =============================================1304 License Management Styles (Complete & Independent)1305 Based on FormsCRM but standalone for FrontBlocks1306 ============================================= */1307 1308 /* License Wrapper - Grid Layout */1309 .formscrm-license-wrapper {1310 display: grid;1311 grid-template-columns: 1fr 320px;1312 gap: 24px;1313 max-width: 1200px;1314 margin: 20px 0;1315 }1316 1317 @media (max-width: 900px) {1318 .formscrm-license-wrapper {1319 grid-template-columns: 1fr;1320 }1321 }1322 1323 /* Main Card */1324 .formscrm-card {1325 background: #fff;1326 border: 1px solid #e5e7eb;1327 border-radius: 12px;1328 padding: 32px;1329 box-shadow: 0 1px 3px rgba(0,0,0,0.05);1330 }1331 1332 .formscrm-card-header {1333 margin-bottom: 24px;1334 padding-bottom: 20px;1335 border-bottom: 1px solid #e5e7eb;1336 }1337 1338 .formscrm-card-header h2 {1339 margin: 0 0 8px 0;1340 font-size: 1.5rem;1341 font-weight: 600;1342 color: #1f2937;1343 }1344 1345 .formscrm-card-header p {1346 margin: 0;1347 color: #6b7280;1348 font-size: 0.875rem;1349 }1350 1351 /* Form Elements */1352 .formscrm-form-group {1353 margin-bottom: 24px;1354 }1355 1356 .formscrm-label {1357 display: block;1358 font-weight: 600;1359 color: #374151;1360 margin-bottom: 8px;1361 font-size: 0.875rem;1362 }1363 1364 .formscrm-input-group {1365 display: flex;1366 gap: 12px;1367 align-items: center;1368 }1369 1370 .formscrm-input {1371 flex: 1;1372 padding: 12px 16px;1373 border: 1px solid #d1d5db;1374 border-radius: 8px;1375 font-size: 1rem;1376 transition: all 0.2s;1377 background: #fff;1378 }1379 1380 .formscrm-input:focus {1381 outline: none;1382 border-color: #8b5cf6;1383 box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.15);1384 }1385 1386 .formscrm-input[readonly] {1387 background: #f9fafb;1388 color: #6b7280;1389 cursor: not-allowed;1390 }1391 1392 /* Deactivate Label */1393 .formscrm-deactivate-label {1394 display: flex;1395 align-items: center;1396 gap: 8px;1397 padding: 12px 16px;1398 background: #fef2f2;1399 border: 1px solid #fecaca;1400 border-radius: 8px;1401 cursor: pointer;1402 transition: background 0.2s;1403 white-space: nowrap;1404 }1405 1406 .formscrm-deactivate-label:hover {1407 background: #fee2e2;1408 }1409 1410 .formscrm-deactivate-label input {1411 margin: 0;1412 }1413 1414 .formscrm-deactivate-label span {1415 font-size: 0.875rem;1416 font-weight: 600;1417 color: #dc2626;1418 }1419 1420 /* Help Text */1421 .formscrm-help-text {1422 margin: 8px 0 0 0;1423 font-size: 0.75rem;1424 color: #9ca3af;1425 }1426 1427 /* Status Box */1428 .formscrm-status-box {1429 display: flex;1430 align-items: center;1431 gap: 12px;1432 padding: 14px 18px;1433 border-radius: 8px;1434 border: 2px solid;1435 }1436 1437 .formscrm-status-active {1438 background: #dcfce7;1439 border-color: #86efac;1440 color: #166534;1441 }1442 1443 .formscrm-status-expired {1444 background: #fee2e2;1445 border-color: #fca5a5;1446 color: #991b1b;1447 }1448 1449 .formscrm-status-inactive {1450 background: #fef9c3;1451 border-color: #fde047;1452 color: #854d0e;1453 }1454 1455 .formscrm-status-icon {1456 display: flex;1457 flex-shrink: 0;1458 }1459 1460 .formscrm-icon,1461 .fcod-icon {1462 width: 22px;1463 height: 22px;1464 }1465 1466 .formscrm-status-text {1467 font-weight: 700;1468 font-size: 1rem;1469 }1470 1471 /* Notices */1472 .formscrm-notice {1473 padding: 14px 18px;1474 border-radius: 8px;1475 margin-bottom: 20px;1476 }1477 1478 .formscrm-notice p {1479 margin: 0;1480 font-size: 0.875rem;1481 line-height: 1.5;1482 }1483 1484 .formscrm-notice a {1485 font-weight: 600;1486 text-decoration: underline;1487 }1488 1489 .formscrm-notice-info {1490 background: #f0f9ff;1491 border: 1px solid #bfdbfe;1492 color: #1e40af;1493 }1494 1495 .formscrm-notice-info a {1496 color: #1d4ed8;1497 }1498 1499 .formscrm-notice-error {1500 background: #fef2f2;1501 border: 1px solid #fecaca;1502 color: #991b1b;1503 }1504 1505 .formscrm-notice-error a {1506 color: #dc2626;1507 }1508 1509 /* Form Actions */1510 .formscrm-form-actions {1511 margin-top: 24px;1512 padding-top: 24px;1513 border-top: 1px solid #e5e7eb;1514 }1515 1516 /* Buttons - FrontBlocks Purple Style */1517 .formscrm-button {1518 display: inline-flex;1519 align-items: center;1520 padding: 12px 24px;1521 border-radius: 8px;1522 font-size: 1rem;1523 font-weight: 600;1524 cursor: pointer;1525 transition: all 0.2s;1526 border: none;1527 }1528 1529 .formscrm-button-primary {1530 background: #8b5cf6;1531 color: #fff;1532 }1533 1534 .formscrm-button-primary:hover {1535 background: #7c3aed;1536 box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);1537 }1538 1539 /* Info Card (Sidebar) */1540 .formscrm-info-card {1541 background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);1542 border: 1px solid #e2e8f0;1543 border-radius: 12px;1544 padding: 24px;1545 height: fit-content;1546 }1547 1548 .formscrm-info-card h3 {1549 margin: 0 0 12px 0;1550 font-size: 1.125rem;1551 font-weight: 700;1552 color: #1e293b;1553 }1554 1555 .formscrm-info-card p {1556 margin: 0 0 16px 0;1557 font-size: 0.875rem;1558 color: #64748b;1559 line-height: 1.5;1560 }1561 1562 /* Benefits List */1563 .formscrm-benefits-list {1564 margin: 0;1565 padding: 0;1566 list-style: none;1567 }1568 1569 .formscrm-benefits-list li {1570 position: relative;1571 padding-left: 28px;1572 margin-bottom: 10px;1573 font-size: 0.875rem;1574 color: #475569;1575 }1576 1577 .formscrm-benefits-list li::before {1578 content: "✓";1579 position: absolute;1580 left: 0;1581 top: 0;1582 color: #8b5cf6;1583 font-weight: 700;1584 font-size: 1.125rem;1585 } -
frontblocks/tags/1.3.3/assets/carousel/frontblocks-advanced-option.js
r3462660 r3472405 1 1 "use strict"; 2 2 3 function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } 4 function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } 5 function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } 3 6 // Add custom controls to the Advanced panel of GenerateBlocks Grid block 4 7 var addFilter = wp.hooks.addFilter; 5 var Fragment = wp.element.Fragment; 8 var _wp$element = wp.element, 9 Fragment = _wp$element.Fragment, 10 useEffect = _wp$element.useEffect, 11 useRef = _wp$element.useRef; 6 12 var _wp$blockEditor = wp.blockEditor, 7 13 InspectorControls = _wp$blockEditor.InspectorControls, … … 13 19 ToggleControl = _wp$components.ToggleControl; 14 20 var __ = wp.i18n.__; 21 22 /** 23 * Returns the document that renders block content. 24 * WordPress 6.x uses an <iframe> for the editor canvas. 25 */ 26 function getEditorDocument() { 27 var iframe = document.querySelector('iframe[name="editor-canvas"]'); 28 return iframe && iframe.contentDocument && iframe.contentDocument.body ? iframe.contentDocument : document; 29 } 30 var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-/; 31 32 /** 33 * Walk an element's subtree to find the container whose DIRECT children 34 * are actual blocks (UUID data-block). Stops at depth 4. 35 */ 36 function findSlidesParent(el, depth) { 37 if (depth === 0) return null; 38 if (Array.from(el.children).some(function (c) { 39 return UUID_RE.test(c.dataset.block || ''); 40 })) { 41 return el; 42 } 43 var _iterator = _createForOfIteratorHelper(el.children), 44 _step; 45 try { 46 for (_iterator.s(); !(_step = _iterator.n()).done;) { 47 var child = _step.value; 48 var found = findSlidesParent(child, depth - 1); 49 if (found) return found; 50 } 51 } catch (err) { 52 _iterator.e(err); 53 } finally { 54 _iterator.f(); 55 } 56 return null; 57 } 58 59 /** 60 * Find the grid DOM element for a given block. 61 * 62 * For generateblocks/element: [data-block][data-type] IS the gb-element. 63 * Do NOT search inside – that returns a child item. 64 * For generateblocks/grid: look for .gb-grid-wrapper inside. 65 * For core/group: walk the subtree to find the element whose children 66 * are the real blocks, because WP nests them differently across versions. 67 */ 68 function findGridEl(blockEl, name) { 69 if (name === 'generateblocks/element') { 70 return blockEl; 71 } 72 if (name === 'generateblocks/grid') { 73 if (blockEl.classList.contains('gb-grid-wrapper')) return blockEl; 74 var grid = blockEl.querySelector('.gb-grid-wrapper'); 75 return grid || null; 76 } 77 if (name === 'core/group') { 78 // Walk up to 4 levels deep to find where the child blocks live. 79 return findSlidesParent(blockEl, 4) || blockEl; 80 } 81 return null; 82 } 15 83 function addCustomCarouselPanel(BlockEdit) { 16 84 return function (props) { 17 // Support grid blocks, element blocks with grid display, and core/group blocks18 85 if (props.name !== 'generateblocks/grid' && props.name !== 'generateblocks/element' && props.name !== 'core/group') { 19 86 return /*#__PURE__*/React.createElement(BlockEdit, props); 20 87 } 21 22 // For element blocks, only show carousel options if it has grid display23 88 if (props.name === 'generateblocks/element') { 24 89 var styles = props.attributes.styles || {}; … … 27 92 } 28 93 } 29 30 // For core/group blocks, only show carousel options if it has grid layout31 94 if (props.name === 'core/group') { 32 95 var layout = props.attributes.layout || {}; … … 48 111 _props$attributes$frb6 = _props$attributes.frblAutoplay, 49 112 frblAutoplay = _props$attributes$frb6 === void 0 ? '' : _props$attributes$frb6, 50 _props$attributes$frb7 = _props$attributes.frblButtons, 51 frblButtons = _props$attributes$frb7 === void 0 ? 'arrows' : _props$attributes$frb7, 52 _props$attributes$frb8 = _props$attributes.frblRewind, 53 frblRewind = _props$attributes$frb8 === void 0 ? true : _props$attributes$frb8, 113 _props$attributes$frb7 = _props$attributes.frblGap, 114 frblGap = _props$attributes$frb7 === void 0 ? '20' : _props$attributes$frb7, 115 _props$attributes$frb8 = _props$attributes.frblButtons, 116 frblButtons = _props$attributes$frb8 === void 0 ? 'arrows' : _props$attributes$frb8, 117 _props$attributes$frb9 = _props$attributes.frblRewind, 118 frblRewind = _props$attributes$frb9 === void 0 ? true : _props$attributes$frb9, 54 119 frblButtonColor = _props$attributes.frblButtonColor, 55 120 frblButtonBgColor = _props$attributes.frblButtonBgColor, 56 _props$attributes$frb9 = _props$attributes.frblButtonsPosition, 57 frblButtonsPosition = _props$attributes$frb9 === void 0 ? 'side' : _props$attributes$frb9, 58 _props$attributes$frb0 = _props$attributes.frblDisableOnDesktop, 59 frblDisableOnDesktop = _props$attributes$frb0 === void 0 ? false : _props$attributes$frb0; 121 _props$attributes$frb0 = _props$attributes.frblButtonsPosition, 122 frblButtonsPosition = _props$attributes$frb0 === void 0 ? 'side' : _props$attributes$frb0, 123 _props$attributes$frb1 = _props$attributes.frblDisableOnDesktop, 124 frblDisableOnDesktop = _props$attributes$frb1 === void 0 ? false : _props$attributes$frb1; 125 126 // ── Editor carousel preview ────────────────────────────────────────── 127 var stateRef = useRef(null); 128 useEffect(function () { 129 var mounted = true; 130 var timer = null; 131 function cleanup() { 132 if (!stateRef.current) return; 133 var _stateRef$current = stateRef.current, 134 gridEl = _stateRef$current.gridEl, 135 slides = _stateRef$current.slides, 136 spacer = _stateRef$current.spacer, 137 prevBtn = _stateRef$current.prevBtn, 138 nextBtn = _stateRef$current.nextBtn, 139 resizeObs = _stateRef$current.resizeObs, 140 scrollFn = _stateRef$current.scrollFn; 141 142 // Disconnect observer and scroll listener. 143 if (resizeObs) resizeObs.disconnect(); 144 var editorDoc = getEditorDocument(); 145 var editorScrollEl = editorDoc.documentElement || editorDoc.body; 146 if (scrollFn) editorScrollEl.removeEventListener('scroll', scrollFn, true); 147 148 // Remove arrows from outer window body (completely outside React). 149 [prevBtn, nextBtn].forEach(function (btn) { 150 if (btn && btn.parentNode) btn.parentNode.removeChild(btn); 151 }); 152 153 // Remove right spacer element. 154 if (spacer && spacer.parentNode) spacer.parentNode.removeChild(spacer); 155 156 // Restore gridEl styles. 157 try { 158 gridEl.classList.remove('frbl-carousel-noscrollbar'); 159 ['display', 'flex-wrap', 'gap', 'overflow-x', 'scroll-behavior', 'padding-left', 'padding-right'].forEach(function (p) { 160 return gridEl.style.removeProperty(p); 161 }); 162 slides.forEach(function (slide) { 163 ['flex-shrink', 'width', 'min-width', 'margin-left', 'margin-right', 'grid-column'].forEach(function (p) { 164 return slide.style.removeProperty(p); 165 }); 166 }); 167 } catch (e) {} 168 stateRef.current = null; 169 } 170 function init() { 171 if (!mounted) return; 172 cleanup(); 173 var editorDoc = getEditorDocument(); 174 175 // GB 2.x wraps blocks in a root element that shares the same data-block UUID. 176 // Use data-type to select the correct inner element; fall back for native blocks. 177 var blockEl = editorDoc.querySelector("[data-block=\"".concat(props.clientId, "\"][data-type=\"").concat(props.name, "\"]")); 178 if (!blockEl) { 179 blockEl = editorDoc.querySelector("[data-block=\"".concat(props.clientId, "\"]")); 180 } 181 if (!blockEl) return; 182 var gridEl = findGridEl(blockEl, props.name); 183 if (!gridEl) return; 184 185 // Slides = direct children that are real blocks (UUID data-block). 186 var slides = Array.from(gridEl.children).filter(function (el) { 187 return UUID_RE.test(el.dataset.block || ''); 188 }); 189 if (slides.length === 0) return; 190 var perView = Math.max(1, parseInt(frblItemsToView) || 4); 191 var gap = Math.max(0, parseInt(frblGap) || 20); 192 var btnColor = frblButtonColor || '#fff'; 193 var btnBg = frblButtonBgColor || 'rgba(0,0,0,0.45)'; 194 195 // Measure content-box width before any style changes. 196 var editorWin = editorDoc.defaultView || window; 197 var ARROW_W = 40; // px reserved on each side for arrow buttons. 198 var cs = editorWin.getComputedStyle(gridEl); 199 var innerW = gridEl.getBoundingClientRect().width - (parseFloat(cs.paddingLeft) || 0) - (parseFloat(cs.paddingRight) || 0); 200 var totalWidth = Math.round(innerW) || 600; 201 // Content area after reserving space for both arrow buttons. 202 var contentW = totalWidth - ARROW_W * 2; 203 var slideWidth = Math.round((contentW - gap * (perView - 1)) / perView); 204 var step = slideWidth + gap; 205 206 // ── Apply scroll-based layout directly to gridEl ───────────── 207 // No DOM restructuring → no React reconciliation conflicts. 208 gridEl.classList.add('frbl-carousel-noscrollbar'); 209 gridEl.style.display = 'flex'; 210 gridEl.style.flexWrap = 'nowrap'; 211 gridEl.style.gap = gap + 'px'; 212 gridEl.style.overflowX = 'scroll'; 213 gridEl.style.scrollBehavior = 'smooth'; 214 // paddingLeft creates left space for the prev arrow. 215 // paddingRight is NOT used because Chrome ignores it in scroll extent; 216 // a spacer flex child is appended instead to guarantee right-side space. 217 gridEl.style.paddingLeft = ARROW_W + 'px'; 218 gridEl.style.paddingRight = '0'; 219 slides.forEach(function (slide) { 220 slide.style.flexShrink = '0'; 221 slide.style.width = slideWidth + 'px'; 222 slide.style.minWidth = slideWidth + 'px'; 223 slide.style.marginLeft = '0'; 224 slide.style.marginRight = '0'; 225 slide.style.gridColumn = 'unset'; 226 }); 227 228 // Right-side spacer: Chrome does not include padding-right in horizontal 229 // scroll extent, so we use a real flex child to guarantee right space. 230 var appender = gridEl.querySelector('.block-list-appender'); 231 var spacer = editorDoc.createElement('span'); 232 spacer.setAttribute('data-frbl-spacer', '1'); 233 spacer.style.cssText = "display:block;flex-shrink:0;width:".concat(ARROW_W, "px;min-width:").concat(ARROW_W, "px;"); 234 gridEl.insertBefore(spacer, appender || null); 235 236 // ── Navigation (scrollLeft, infinite loop) ─────────────────── 237 var idx = 0; 238 function scrollTo(n) { 239 var total = slides.length; 240 if (n >= total) { 241 // Forward past last: instant snap to 0 then continue. 242 gridEl.style.scrollBehavior = 'auto'; 243 gridEl.scrollLeft = 0; 244 void gridEl.offsetWidth; 245 gridEl.style.scrollBehavior = 'smooth'; 246 idx = 0; 247 return; 248 } 249 if (n < 0) { 250 // Back past first: instant snap to last. 251 gridEl.style.scrollBehavior = 'auto'; 252 gridEl.scrollLeft = Math.round((total - 1) * step); 253 void gridEl.offsetWidth; 254 gridEl.style.scrollBehavior = 'smooth'; 255 idx = total - 1; 256 return; 257 } 258 idx = n; 259 gridEl.scrollLeft = Math.round(idx * step); 260 } 261 262 // ── Arrows in OUTER document body ──────────────────────────── 263 // Placing them outside the iframe means React never touches them. 264 var iframe = document.querySelector('iframe[name="editor-canvas"]'); 265 function updateArrowPos() { 266 if (!stateRef.current) return; 267 var ifrRect = iframe ? iframe.getBoundingClientRect() : { 268 top: 0, 269 left: 0 270 }; 271 var rect = gridEl.getBoundingClientRect(); // coords in iframe viewport 272 var midY = Math.round(ifrRect.top + rect.top + rect.height / 2 - 16); 273 prevBtn.style.top = midY + 'px'; 274 prevBtn.style.left = Math.round(ifrRect.left + rect.left + 8) + 'px'; 275 nextBtn.style.top = midY + 'px'; 276 nextBtn.style.right = Math.round(window.innerWidth - (ifrRect.left + rect.right) + 8) + 'px'; 277 } 278 function makeArrow(dir) { 279 var btn = document.createElement('button'); 280 btn.type = 'button'; 281 btn.className = "frbl-editor-arrow frbl-editor-arrow-".concat(dir); 282 btn.setAttribute('aria-label', dir === 'prev' ? 'Previous slide' : 'Next slide'); 283 btn.style.cssText = "position:fixed;z-index:99999;background-color:".concat(btnBg, ";"); 284 var d = dir === 'prev' ? 'M6 1L1 6L6 11' : 'M1 11L6 6L1 1'; 285 btn.innerHTML = "<svg width=\"7\" height=\"12\" viewBox=\"0 0 7 12\" fill=\"none\"><path d=\"".concat(d, "\" stroke=\"").concat(btnColor, "\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>"); 286 btn.addEventListener('click', function (e) { 287 e.stopPropagation(); 288 scrollTo(dir === 'prev' ? idx - 1 : idx + 1); 289 }); 290 document.body.appendChild(btn); 291 return btn; 292 } 293 var prevBtn = makeArrow('prev'); 294 var nextBtn = makeArrow('next'); 295 updateArrowPos(); 296 297 // Keep arrows positioned correctly when the editor scrolls or resizes. 298 var resizeObs = new ResizeObserver(updateArrowPos); 299 resizeObs.observe(gridEl); 300 var editorScrollEl = editorDoc.documentElement || editorDoc.body; 301 var scrollFn = updateArrowPos; 302 editorScrollEl.addEventListener('scroll', scrollFn, { 303 passive: true, 304 capture: true 305 }); 306 stateRef.current = { 307 gridEl: gridEl, 308 slides: slides, 309 spacer: spacer, 310 prevBtn: prevBtn, 311 nextBtn: nextBtn, 312 resizeObs: resizeObs, 313 scrollFn: scrollFn 314 }; 315 } 316 if (frblGridOption !== 'none') { 317 timer = setTimeout(init, 300); 318 } else { 319 cleanup(); 320 } 321 return function () { 322 mounted = false; 323 if (timer) clearTimeout(timer); 324 cleanup(); 325 }; 326 }, [frblGridOption, frblItemsToView, frblGap, frblButtonColor, frblButtonBgColor, props.clientId]); 327 // ── Inspector panel ────────────────────────────────────────────────── 328 60 329 return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockEdit, props), /*#__PURE__*/React.createElement(InspectorControls, null, /*#__PURE__*/React.createElement(PanelBody, { 61 330 title: __('Carousel Settings', 'frontblocks'), … … 75 344 }], 76 345 onChange: function onChange(value) { 77 props.setAttributes({346 return props.setAttributes({ 78 347 frblGridOption: value 79 348 }); … … 124 393 }); 125 394 } 126 }), frblGridOption === 'slider' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ToggleControl, { 395 }), /*#__PURE__*/React.createElement(TextControl, { 396 label: __('Gap (px)', 'frontblocks'), 397 value: frblGap, 398 onChange: function onChange(value) { 399 return props.setAttributes({ 400 frblGap: value 401 }); 402 }, 403 help: __('Space between slides in pixels. Leave empty for 20.', 'frontblocks') 404 }), frblGridOption === 'slider' && /*#__PURE__*/React.createElement(ToggleControl, { 127 405 label: __('Rewind', 'frontblocks'), 128 406 checked: frblRewind, … … 132 410 }); 133 411 } 134 }) ), /*#__PURE__*/React.createElement(SelectControl, {412 }), /*#__PURE__*/React.createElement(SelectControl, { 135 413 label: __('Buttons', 'frontblocks'), 136 414 value: frblButtons, … … 150 428 }); 151 429 } 152 }), frblButtons === 'arrows' && /*#__PURE__*/React.createElement( React.Fragment, null, /*#__PURE__*/React.createElement(SelectControl, {430 }), frblButtons === 'arrows' && /*#__PURE__*/React.createElement(SelectControl, { 153 431 label: __('Buttons Position', 'frontblocks'), 154 432 value: frblButtonsPosition, … … 165 443 }); 166 444 } 167 }) ), /*#__PURE__*/React.createElement(PanelColorSettings, {445 }), /*#__PURE__*/React.createElement(PanelColorSettings, { 168 446 title: __('Button Colors', 'frontblocks'), 169 447 colorSettings: [{ -
frontblocks/tags/1.3.3/assets/carousel/frontblocks-carousel.css
r3462660 r3472405 1 1 /** 2 * ## Glide Carousel style 3 * ---------------------------*/4 5 . glide {2 * Frontblocks Carousel – scoped under .frontblocks so other Glide instances are not affected. 3 */ 4 5 .frontblocks.glide { 6 6 position: relative; 7 7 width: 100%; 8 max-width: 100%; 8 9 box-sizing: border-box; 9 } 10 .glide * { 10 overflow: visible; 11 margin: 0; 12 padding: 0; 13 } 14 15 .frontblocks.glide * { 11 16 box-sizing: inherit; 12 17 } 13 .glide__track { 18 19 .frontblocks .glide__track { 14 20 overflow: hidden; 15 } 16 .glide__slides { 21 width: 100%; 22 position: relative; 23 left: 0; 24 margin: 0; 25 padding: 0; 26 } 27 28 .frontblocks .glide__slides { 17 29 position: relative; 18 30 width: 100%; … … 28 40 flex-wrap: nowrap; 29 41 will-change: transform; 30 transition: transform 400ms cubic-bezier(0.165, 0.84, 0.44, 1); 31 } 32 .glide__slides--dragging { 33 user-select: none; 34 } 35 .glide__slide { 42 } 43 44 .frontblocks .glide__slides--dragging { 45 user-select: none; 46 } 47 48 .frontblocks .glide__slide { 36 49 width: 100%; 37 50 height: 100%; … … 41 54 -webkit-touch-callout: none; 42 55 -webkit-tap-highlight-color: transparent; 43 } 44 .glide__slide a { 56 min-width: 0; 57 overflow: hidden; 58 } 59 60 /* Prevent inner content (cards, AWB, etc.) from overflowing the slide and being cut off. */ 61 .frontblocks .glide__slide > * { 62 max-width: 100%; 63 box-sizing: border-box; 64 } 65 66 .frontblocks .glide__slide a { 45 67 user-select: none; 46 68 -webkit-user-drag: none; … … 48 70 -ms-user-select: none; 49 71 } 50 .glide__arrows { 72 73 .frontblocks .glide__arrows { 51 74 -webkit-touch-callout: none; 52 75 user-select: none; 53 76 } 54 .glide__bullets { 77 78 .frontblocks .glide__bullets { 55 79 -webkit-touch-callout: none; 56 80 user-select: none; 57 81 } 58 .glide--rtl { 82 83 .frontblocks.glide--rtl { 59 84 direction: rtl; 60 85 } 61 86 62 /*# sourceMappingURL=glide.core.css.map */ 63 64 .glide__arrow { 87 .frontblocks .glide__arrow { 65 88 position: absolute; 66 89 display: block; … … 79 102 line-height: 1; 80 103 } 81 .glide__arrow:focus { 104 105 .frontblocks .glide__arrow:focus { 82 106 outline: none; 83 107 } 84 .glide__arrow:hover { 108 109 .frontblocks .glide__arrow:hover { 85 110 border-color: white; 86 111 } 87 .glide__arrow--left { 88 left: -1em; 89 } 90 .glide__arrow--right { 91 right: -1em; 92 } 93 .glide__arrow--disabled { 112 113 .frontblocks .glide__arrow--left { 114 left: 1em; 115 } 116 117 .frontblocks .glide__arrow--right { 118 right: 1em; 119 } 120 121 .frontblocks .glide__arrow--disabled { 94 122 opacity: 0.33; 95 123 } 96 .glide__bullets { 97 position: absolute; 98 z-index: 2; 99 bottom: -1em; 100 left: 50%; 101 display: inline-flex; 124 125 .frontblocks .glide__bullets { 126 display: flex; 127 justify-content: center; 102 128 list-style: none; 103 transform: translateX(-50%); 104 gap: 5px; 105 } 106 .glide__bullet { 107 background-color: rgba(255, 255, 255, 0.5); 108 width: 13px; 109 height: 13px; 129 gap: 2px; 130 margin: 0.75em 0 0; 131 padding: 0; 132 } 133 134 .frontblocks .glide__bullet { 135 box-sizing: content-box; 136 width: 10px; 137 height: 10px; 110 138 padding: 0; 111 139 border-radius: 50%; 112 border: 2px solid transparent;113 transition: all 300ms ease-in-out;140 border: none; 141 background-color: var(--frbl-bullet-bg, rgba(0, 0, 0, 0.25)); 114 142 cursor: pointer; 115 line-height: 0; 116 margin: 0; 117 } 118 .glide__bullet:focus { 119 outline: none; 120 } 121 .glide__bullet:hover, .glide__bullet:focus { 122 border: 2px solid white; 123 background-color: rgba(255, 255, 255, 0.5); 124 } 125 .glide__bullet--active { 126 background-color: white; 127 } 128 .glide--swipeable { 143 transition: background-color 300ms ease-in-out, transform 300ms ease-in-out; 144 margin: 0 2px; 145 flex-shrink: 0; 146 } 147 148 .frontblocks .glide__bullet:focus { 149 outline: 2px solid var(--frbl-bullet-color, rgba(0, 0, 0, 0.8)); 150 outline-offset: 2px; 151 } 152 153 .frontblocks .glide__bullet:hover { 154 background-color: var(--frbl-bullet-color, rgba(0, 0, 0, 0.8)); 155 transform: scale(1.2); 156 } 157 158 .frontblocks .glide__bullet--active { 159 background-color: var(--frbl-bullet-color, rgba(0, 0, 0, 0.8)); 160 transform: scale(1.2); 161 } 162 163 .frontblocks.glide--swipeable { 129 164 cursor: grab; 130 165 cursor: -moz-grab; 131 166 cursor: -webkit-grab; 132 167 } 133 .glide--dragging { 168 169 .frontblocks.glide--dragging { 134 170 cursor: grabbing; 135 171 cursor: -moz-grabbing; 136 172 cursor: -webkit-grabbing; 137 173 } 138 .glide__arrows--bottom .glide__arrow { 139 top: calc(100% + 25px); 140 left: 0; 141 } 142 .glide__arrows--bottom .glide__arrow--right { 143 left: 50px; 144 right: unset; 145 } 146 /* Arrows position top/side - spans full container width */ 147 .glide__arrows--top { 148 position: absolute; 149 top: 50%; 150 left: 0; 151 right: 0; 152 width: 100%; 153 z-index: 10; 154 pointer-events: none; 155 transform: translateY(-50%); 156 } 157 .glide__arrows--top .glide__arrow { 158 pointer-events: all; 159 } 160 .glide__arrows--top .glide__arrow--left { 161 left: 2em; 162 } 163 .glide__arrows--top .glide__arrow--right { 164 right: 2em; 165 } 166 /* Responsive */ 174 175 .frontblocks .glide__arrows--bottom .glide__arrow { 176 top: calc(100% + 25px); 177 left: 0; 178 } 179 180 .frontblocks .glide__arrows--bottom .glide__arrow--right { 181 left: 50px; 182 right: unset; 183 } 184 185 .frontblocks .glide__arrows--top { 186 position: absolute; 187 top: 50%; 188 left: 0; 189 right: 0; 190 width: 100%; 191 z-index: 10; 192 pointer-events: none; 193 transform: translateY(-50%); 194 } 195 196 .frontblocks .glide__arrows--top .glide__arrow { 197 pointer-events: all; 198 } 199 200 .frontblocks .glide__arrows--top .glide__arrow--left { 201 left: 2em; 202 } 203 204 .frontblocks .glide__arrows--top .glide__arrow--right { 205 right: 2em; 206 } 207 167 208 @media only screen and (max-width: 768px) { 168 .glide__arrow--left { 169 left: 0; 170 } 171 .glide__arrow--right { 172 right: 0; 173 } 174 } 175 176 /*# sourceMappingURL=glide.theme.css.map */ 209 .frontblocks .glide__arrow--left { 210 left: 0.5em; 211 } 212 .frontblocks .glide__arrow--right { 213 right: 0.5em; 214 } 215 } 177 216 178 217 /** 179 * Override native Gutenberg Grid styles when carousel is active 218 * Override native Gutenberg Grid styles when carousel is active (scoped to frontblocks carousel). 180 219 */ 181 220 .wp-block-group.frontblocks-carousel, 182 221 .wp-block-group.frontblocks-carousel.is-layout-grid { 183 display: block; 184 grid-template-columns: none; 185 gap: 0; 222 display: block; 223 grid-template-columns: none; 224 gap: 0; 225 } 226 227 .wp-block-group.frontblocks-carousel .frontblocks.glide, 228 .wp-block-group.frontblocks-carousel .frontblocks .glide__track { 229 width: 100%; 230 max-width: 100%; 231 margin-left: 0; 232 margin-right: 0; 233 padding-left: 0; 234 padding-right: 0; 186 235 } 187 236 188 237 .wp-block-group.frontblocks-carousel > * { 189 width: 100%; 190 } 191 192 /* Ensure inner container doesn't interfere with carousel */ 238 width: 100%; 239 } 240 193 241 .wp-block-group.frontblocks-carousel > .wp-block-group__inner-container { 194 display: block; 195 grid-template-columns: none; 196 gap: 0; 197 width: 100%; 198 } 199 200 /* Override grid styles for direct children in carousel mode */ 201 .glide__slides.wp-block-group, 202 .glide__slides.wp-block-group.is-layout-grid { 203 display: flex; 204 grid-template-columns: none; 205 gap: 0; 206 column-gap: 0; 207 row-gap: 0; 208 } 209 210 /* Ensure slides have proper width */ 211 .glide__slides > .glide__slide { 212 min-width: 0; 213 flex-shrink: 0; 214 } 215 216 /* Force full width for single slide view */ 217 .frontblocks-carousel[data-view="1"] .glide__slide { 218 margin-left: 0; 219 margin-right: 0; 220 } 221 222 /* Remove gaps when showing one slide */ 223 .frontblocks-carousel[data-view="1"].glide__slides { 224 gap: 0; 225 } 226 227 /* Responsive single slide view */ 228 @media only screen and (max-width: 768px) { 229 .frontblocks-carousel[data-mobile-view="1"] .glide__slide { 230 width: 100%; 231 flex: 0 0 100%; 232 max-width: 100%; 233 margin-left: 0; 234 margin-right: 0; 235 } 236 } 237 238 @media only screen and (min-width: 769px) and (max-width: 1024px) { 239 .frontblocks-carousel[data-tablet-view="1"] .glide__slide { 240 width: 100%; 241 flex: 0 0 100%; 242 max-width: 100%; 243 margin-left: 0; 244 margin-right: 0; 245 } 246 } 247 248 @media only screen and (min-width: 1025px) and (max-width: 1440px) { 249 .frontblocks-carousel[data-laptop-view="1"] .glide__slide { 250 width: 100%; 251 flex: 0 0 100%; 252 max-width: 100%; 253 margin-left: 0; 254 margin-right: 0; 255 } 256 } 257 258 /* Handle alignfull content within carousel slides */ 259 .glide__slide > .wp-block-cover.alignfull, 260 .glide__slide > .alignfull { 261 width: 100%; 262 max-width: none; 263 margin-left: 0; 264 margin-right: 0; 265 } 266 267 /* Ensure cover blocks maintain minimum height */ 268 .glide__slide .wp-block-cover { 269 min-height: 430px; 270 display: flex; 271 align-items: center; 272 justify-content: center; 273 } 274 275 /* Prevent carousel from overflowing viewport */ 276 .glide { 277 position: relative; 278 overflow: visible; 279 min-height: 430px; 280 } 281 282 .glide__track { 283 overflow: hidden; 284 width: 100%; 285 position: relative; 286 z-index: 1; 287 } 288 289 .glide__slides { 290 position: relative; 291 z-index: 1; 292 height: auto; 293 min-height: 430px; 294 } 295 296 .glide__slide { 297 position: relative; 298 z-index: 1; 299 height: auto; 300 opacity: 1; 301 visibility: visible; 302 } 242 display: block; 243 grid-template-columns: none; 244 gap: 0; 245 width: 100%; 246 } 247 248 .frontblocks .glide__slides.wp-block-group, 249 .frontblocks .glide__slides.wp-block-group.is-layout-grid { 250 display: flex; 251 grid-template-columns: none; 252 gap: 0; 253 column-gap: 0; 254 row-gap: 0; 255 } 256 257 .frontblocks .glide__slides > .glide__slide { 258 min-width: 0; 259 flex-shrink: 0; 260 } 261 262 /** 263 * GenerateBlocks (and any other plugin) may inject column-gap via generated 264 * utility classes on the carousel slides container. Glide manages its own 265 * spacing through margin-right on each slide, so any external column-gap 266 * breaks the width calculation and must be zeroed out. 267 */ 268 .frontblocks-carousel, 269 .frontblocks .glide__slides { 270 column-gap: 0 !important; 271 gap: 0 !important; 272 } -
frontblocks/tags/1.3.3/assets/carousel/frontblocks-carousel.js
r3462660 r3472405 29 29 parentwrap.replaceChild(wrapperParent, wrapper); 30 30 wrapperParent.appendChild(wrapper); 31 wrapperParent.classList.add(' glide');31 wrapperParent.classList.add('frontblocks', 'glide'); 32 32 33 33 // Options … … 38 38 const carouselTabletView = item.getAttribute('data-tablet-view') ? parseInt(item.getAttribute('data-tablet-view')) : 2; 39 39 const carouselMobileView = item.getAttribute('data-mobile-view') ? parseInt(item.getAttribute('data-mobile-view')) : 1; 40 const autoplayValue = item.getAttribute('data-autoplay'); 41 const carouselAutoplay = autoplayValue && autoplayValue !== '' ? parseInt(autoplayValue) : 0; 40 const autoplayAttr = item.getAttribute('data-autoplay'); 41 const carouselAutoplay = (autoplayAttr !== '' && autoplayAttr !== null && autoplayAttr !== undefined) ? parseInt(autoplayAttr, 10) : 0; 42 const carouselGap = item.getAttribute('data-gap') ? parseInt(item.getAttribute('data-gap'), 10) : 20; 42 43 const carouselRewind = item.getAttribute('data-rewind') ? item.getAttribute('data-rewind') : false; 43 44 const carouselbuttonsColor = item.getAttribute('data-buttons-color') ? item.getAttribute('data-buttons-color') : 'black'; … … 64 65 bullets.classList.add('glide__bullets'); 65 66 bullets.setAttribute('data-glide-el', 'controls[nav]'); 67 bullets.setAttribute('role', 'group'); 68 bullets.setAttribute('aria-label', 'Slide navigation'); 66 69 67 70 for (let i = 0; i < item.children.length; i++) { … … 70 73 bullet.setAttribute('data-glide-dir', '=' + i); 71 74 bullet.setAttribute('aria-label', 'Go to slide ' + (i + 1)); 72 bullet.style.backgroundColor = carouselbuttonsBackgroundColor;73 75 bullets.appendChild(bullet); 74 76 } … … 76 78 wrapperParent.appendChild(bullets); 77 79 78 // Add custom CSS for active bullet color79 const style = document.createElement('style');80 style.textContent = `81 .glide__bullet.glide__bullet--active { 82 background-color: ${carouselbuttonsColor} !important; 83 } 84 `;85 document.head.appendChild(style);80 // Set bullet colors via CSS custom properties on the wrapper. 81 // This avoids specificity conflicts with the stylesheet. 82 if (carouselbuttonsColor) { 83 wrapperParent.style.setProperty('--frbl-bullet-color', carouselbuttonsColor); 84 } 85 if (carouselbuttonsBackgroundColor && carouselbuttonsBackgroundColor !== 'transparent') { 86 wrapperParent.style.setProperty('--frbl-bullet-bg', carouselbuttonsBackgroundColor); 87 } 86 88 } 87 89 … … 110 112 wrapperParent.appendChild(arrows); 111 113 } 112 // Calculate gap based on perView - use 0 gap when showing 1 slide113 const calculateGap = (view) => view === 1 ? 0 : 20;114 115 114 const glideFrontBlocks = new Glide(wrapperParent, { 116 115 type: carouselType, 117 116 perView: carouselView, 118 117 startAt: 0, 119 autoplay: carouselAutoplay === 0 ? false : carouselAutoplay,120 gap: calculateGap(carouselView),118 autoplay: carouselAutoplay > 0 ? carouselAutoplay : false, 119 gap: isNaN(carouselGap) ? 20 : carouselGap, 121 120 rewind: carouselRewind, 122 121 breakpoints: { 123 122 768: { 124 perView: carouselMobileView, 125 gap: calculateGap(carouselMobileView) 123 perView: carouselMobileView 126 124 }, 127 125 1024: { 128 perView: carouselTabletView, 129 gap: calculateGap(carouselTabletView) 126 perView: carouselTabletView 130 127 }, 131 128 1440: { 132 perView: carouselLaptopView, 133 gap: calculateGap(carouselLaptopView) 129 perView: carouselLaptopView 134 130 } 135 131 } -
frontblocks/tags/1.3.3/assets/gravityforms-inline/frontblocks-gf-inline.css
r3402582 r3472405 174 174 } 175 175 176 /* ------------------------------------------------------------------------- 177 GenerateBlocks Accordion + Gravity Form: remove blank space when closed 178 When a Gravity Form is inside a GB accordion and the accordion is above 179 the footer, the closed content can still reserve space. Force it to none. 180 ------------------------------------------------------------------------- */ 181 .gb-accordion__item:not(.gb-accordion__item-open):not([data-accordion-is-open="true"]) > .gb-accordion__content { 182 display: none; 183 overflow: hidden; 184 max-height: 0; 185 min-height: 0 ; 186 margin: 0 ; 187 padding: 0 ; 188 visibility: hidden; 189 } 190 191 /* Prevent Gravity Form wrapper from forcing height when inside closed accordion. */ 192 .gb-accordion__item:not(.gb-accordion__item-open):not([data-accordion-is-open="true"]) > .gb-accordion__content .gform_wrapper { 193 min-height: 0; 194 height: 0; 195 overflow: hidden; 196 visibility: hidden; 197 } 198 -
frontblocks/tags/1.3.3/assets/shape-animations/frontblocks-shape-animation-option.js
r3409365 r3472405 19 19 PanelBody = _wp$components.PanelBody, 20 20 ToggleControl = _wp$components.ToggleControl, 21 TextareaControl = _wp$components.TextareaControl, 21 22 Button = _wp$components.Button, 22 Notice = _wp$components.Notice, 23 FormFileUpload = _wp$components.FormFileUpload; 23 Notice = _wp$components.Notice; 24 24 25 25 /** … … 46 46 jsonPreview = _useState4[0], 47 47 setJsonPreview = _useState4[1]; 48 var _useState5 = useState(''),49 _useState6 = _slicedToArray(_useState5, 2),50 fileName = _useState6[0],51 setFileName = _useState6[1];52 var _useState7 = useState(0),53 _useState8 = _slicedToArray(_useState7, 2),54 fileInputKey = _useState8[0],55 setFileInputKey = _useState8[1];56 48 57 49 // Detect if JSON is Lottie format. … … 101 93 }; 102 94 103 // Handle file upload. 104 var handleFileUpload = function handleFileUpload(event) { 105 var file = event.target.files[0]; 106 if (!file) { 107 return; 108 } 109 110 // Check if it's a JSON file. 111 if (!file.name.endsWith('.json')) { 112 setJsonError(__('Please select a JSON file', 'frontblocks')); 113 setFileInputKey(function(prev) { return prev + 1; }); 114 return; 115 } 116 117 setFileName(file.name); 118 119 // Read file content. 120 var reader = new FileReader(); 121 reader.onload = function(e) { 122 var content = e.target.result; 123 setAttributes({ frblCustomSvgAnimationJson: content }); 124 validateJson(content); 125 setFileInputKey(function(prev) { return prev + 1; }); 126 }; 127 reader.onerror = function() { 128 setJsonError(__('Error reading file', 'frontblocks')); 129 setFileInputKey(function(prev) { return prev + 1; }); 130 }; 131 reader.readAsText(file); 95 // Handle JSON change. 96 var handleJsonChange = function handleJsonChange(value) { 97 setAttributes({ 98 frblCustomSvgAnimationJson: value 99 }); 100 if (value.trim()) { 101 validateJson(value); 102 } else { 103 setJsonError(''); 104 setJsonPreview(null); 105 } 132 106 }; 133 134 // Clear imported JSON. 135 var handleClear = function handleClear() { 136 setAttributes({ frblCustomSvgAnimationJson: '' }); 137 setJsonError(''); 138 setJsonPreview(null); 139 setFileName(''); 140 setFileInputKey(function(prev) { return prev + 1; }); 141 }; 142 107 143 108 // Example JSON template. 144 109 var exampleJson = JSON.stringify({ … … 153 118 } 154 119 }, null, 2); 155 156 // Download example JSON.157 var handleDownloadExample = function handleDownloadExample() {158 var blob = new Blob([exampleJson], { type: 'application/json' });159 var url = URL.createObjectURL(blob);160 var a = document.createElement('a');161 a.href = url;162 a.download = 'example-animation.json';163 document.body.appendChild(a);164 a.click();165 document.body.removeChild(a);166 URL.revokeObjectURL(url);167 };168 169 120 return wp.element.createElement(Fragment, {}, wp.element.createElement(BlockEdit, props), wp.element.createElement(InspectorControls, {}, wp.element.createElement(PanelBody, { 170 121 title: __('FrontBlocks Custom SVG Animation', 'frontblocks'), … … 182 133 style: { 183 134 fontSize: '12px', 184 marginBottom: ' 12px',135 marginBottom: '8px', 185 136 color: '#757575' 186 137 } 187 }, __('Import a JSON file with your animation configuration:', 'frontblocks')), wp.element.createElement(FormFileUpload, { 188 key: fileInputKey, 189 accept: '.json', 190 onChange: handleFileUpload, 191 render: function(ref) { 192 return wp.element.createElement(Button, { 193 isSecondary: true, 194 onClick: ref.openFileDialog, 195 style: { marginBottom: '8px', width: '100%' } 196 }, fileName ? __('Change JSON file', 'frontblocks') : __('Import JSON file', 'frontblocks')); 197 } 198 }), fileName && wp.element.createElement('div', { 199 style: { 200 display: 'flex', 201 alignItems: 'center', 202 justifyContent: 'space-between', 203 marginBottom: '12px', 204 padding: '8px', 205 background: '#f6f7f7', 206 borderRadius: '4px', 207 fontSize: '12px' 208 } 209 }, wp.element.createElement('span', {}, '📄 ' + fileName), wp.element.createElement(Button, { 210 isSmall: true, 211 isDestructive: true, 212 onClick: handleClear 213 }, __('Clear', 'frontblocks'))), jsonError && wp.element.createElement(Notice, { 138 }, __('Paste your JSON configuration below:', 'frontblocks')), wp.element.createElement(TextareaControl, { 139 label: __('JSON Configuration', 'frontblocks'), 140 value: frblCustomSvgAnimationJson, 141 onChange: handleJsonChange, 142 rows: 10, 143 help: __('JSON with svg and animation properties', 'frontblocks') 144 }), jsonError && wp.element.createElement(Notice, { 214 145 status: 'error', 215 146 isDismissible: false … … 228 159 marginBottom: '8px' 229 160 } 230 }, __('📋 Downloadexample JSON', 'frontblocks')), wp.element.createElement('pre', {161 }, __('📋 Show example JSON', 'frontblocks')), wp.element.createElement('pre', { 231 162 style: { 232 163 background: '#f6f7f7', … … 240 171 isSecondary: true, 241 172 isSmall: true, 242 onClick: handleDownloadExample,243 style: {244 marginTop: '8px',245 marginRight: '8px'246 }247 }, __('Download example', 'frontblocks')), wp.element.createElement(Button, {248 isSecondary: true,249 isSmall: true,250 173 onClick: function onClick() { 251 174 setAttributes({ 252 175 frblCustomSvgAnimationJson: exampleJson 253 176 }); 254 setFileName('example-animation.json');255 177 validateJson(exampleJson); 256 setFileInputKey(function(prev) { return prev + 1; });257 178 }, 258 179 style: { -
frontblocks/tags/1.3.3/assets/stacked-images/frontblocks-stacked-images-frontend.js
r3462660 r3472405 78 78 entries.forEach(entry => { 79 79 if (entry.isIntersecting) { 80 container.classList.add('frbl-animated'); 80 81 animateImages(images, duration, delay); 81 82 observer.unobserve(entry.target); … … 84 85 }, 85 86 { 86 threshold: 0. 2,87 rootMargin: ' 0px',87 threshold: 0.05, 88 rootMargin: '50px 0px 50px 0px', 88 89 } 89 90 ); 90 91 91 92 observer.observe(container); 93 94 // Fallback: if observer never fires (e.g. layout/height issue on mobile), animate after a short delay. 95 setTimeout(() => { 96 if (!container.classList.contains('frbl-animated')) { 97 container.classList.add('frbl-animated'); 98 animateImages(images, duration, delay); 99 } 100 }, 800); 92 101 }); 93 102 } -
frontblocks/tags/1.3.3/assets/stacked-images/frontblocks-stacked-images.css
r3462660 r3472405 3 3 */ 4 4 5 /* Wrapper */5 /* Wrapper – centered, compact size on all viewports */ 6 6 .frbl-stacked-images-wrapper { 7 7 position: relative; 8 8 width: 100%; 9 max-width: 520px; 10 max-height: 65vh; 11 margin-left: auto; 12 margin-right: auto; 9 13 overflow: visible; 10 14 display: block; 11 15 background: transparent; 12 padding: 50px;13 margin: -50px;16 padding: 40px; 17 box-sizing: border-box; 14 18 } 15 19 16 /* Container */20 /* Container – center content horizontally and vertically */ 17 21 .frbl-stacked-images-container { 18 22 position: relative; … … 23 27 justify-content: center; 24 28 overflow: visible; 29 margin: 0 auto; 25 30 } 26 31 27 /* Individual image */32 /* Individual image – flex center so img is always centered */ 28 33 .frbl-stacked-image { 29 34 position: absolute; 30 35 top: 0; 31 36 left: 0; 37 right: 0; 38 bottom: 0; 32 39 width: 100%; 33 40 height: 100%; … … 39 46 visibility: hidden; 40 47 overflow: visible; 48 margin: auto; 41 49 } 42 50 … … 47 55 48 56 .frbl-stacked-image img { 49 max-width: 100%;50 max-height: 100%;57 max-width: 85%; 58 max-height: 85%; 51 59 width: auto; 52 60 height: auto; 53 61 object-fit: contain; 62 object-position: center; 54 63 display: block; 64 margin: auto; 55 65 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 56 66 } … … 99 109 } 100 110 101 /* Responsive */ 111 /* Tablet / ventana media: aquí suele verse enorme, lo limitamos mucho */ 112 @media (min-width: 769px) and (max-width: 1200px) { 113 .frbl-stacked-images-wrapper { 114 max-width: 420px; 115 max-height: 55vh; 116 padding: 24px; 117 } 118 .frbl-stacked-image img { 119 max-width: 82%; 120 max-height: 82%; 121 } 122 } 123 124 /* Mobile */ 102 125 @media (max-width: 768px) { 103 126 .frbl-stacked-images-wrapper { 104 height: auto !important; 105 min-height: 300px; 127 min-height: 260px; 128 max-height: 60vh; 129 max-width: 88%; 130 margin-left: auto; 131 margin-right: auto; 132 padding: 20px; 133 } 134 .frbl-stacked-images-container { 135 min-height: 260px; 136 margin: 0 auto; 137 } 138 .frbl-stacked-image img { 139 max-width: 85%; 140 max-height: 55vh; 141 object-position: center; 142 margin: auto; 106 143 } 107 144 } -
frontblocks/tags/1.3.3/frontblocks.php
r3462660 r3472405 1 1 <?php 2 2 /** 3 * Plugin Name: FrontBlocks for G eneratePress3 * Plugin Name: FrontBlocks for Gutenberg/GeneratePress 4 4 * Plugin URI: https://wordpress.org/plugins/frontblocks/ 5 * Description: Blocks and helpers that extends G eneratePress blocks.6 * Version: 1.3. 25 * Description: Blocks and helpers that extends Gutenberg and GeneratePress blocks. 6 * Version: 1.3.3 7 7 * Author: Closemarketing 8 8 * Author URI: https://close.marketing … … 27 27 defined( 'ABSPATH' ) || die( 'No script kiddies please!' ); 28 28 29 define( 'FRBL_VERSION', '1.3. 2' );29 define( 'FRBL_VERSION', '1.3.3' ); 30 30 define( 'FRBL_PLUGIN', __FILE__ ); 31 31 define( 'FRBL_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); -
frontblocks/tags/1.3.3/includes/Frontend/Carousel.php
r3409365 r3472405 34 34 private function init_hooks() { 35 35 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) ); 36 add_action( 'enqueue_block_assets', array( $this, 'enqueue_block_canvas_assets' ) ); 36 37 add_filter( 'render_block_generateblocks/grid', array( $this, 'add_custom_attributes_to_grid_block' ), 10, 2 ); 37 38 add_filter( 'render_block_generateblocks/element', array( $this, 'add_custom_attributes_to_element_block' ), 10, 2 ); 38 39 add_filter( 'render_block_core/group', array( $this, 'add_custom_attributes_to_core_group_block' ), 10, 2 ); 39 40 add_action( 'init', array( $this, 'register_custom_attributes' ), 5 ); 41 } 42 43 /** 44 * Enqueue carousel CSS in the editor canvas (iframe). 45 * 46 * @return void 47 */ 48 public function enqueue_block_canvas_assets() { 49 if ( ! is_admin() ) { 50 return; 51 } 52 wp_enqueue_style( 53 'frontblocks-carousel-editor', 54 FRBL_PLUGIN_URL . 'assets/carousel/frontblocks-carousel-editor.css', 55 array(), 56 FRBL_VERSION 57 ); 40 58 } 41 59 … … 76 94 $responsive_to_view = isset( $attrs['frblResponsiveToView'] ) ? (int) $attrs['frblResponsiveToView'] : 1; 77 95 $autoplay = isset( $attrs['frblAutoplay'] ) ? ( (int) $attrs['frblAutoplay'] * 1000 ) : ''; 96 $gap = isset( $attrs['frblGap'] ) && '' !== $attrs['frblGap'] ? (int) $attrs['frblGap'] : 20; 78 97 $rewind = isset( $attrs['frblRewind'] ) ? (bool) $attrs['frblRewind'] : true; 79 98 $buttons = isset( $attrs['frblButtons'] ) ? sanitize_text_field( $attrs['frblButtons'] ) : 'arrows'; … … 100 119 ' data-mobile-view="' . esc_attr( $responsive_to_view ) . '"' . 101 120 ' data-autoplay="' . esc_attr( $autoplay ) . '"' . 121 ' data-gap="' . esc_attr( $gap ) . '"' . 102 122 ' data-buttons="' . esc_attr( $buttons ) . '"' . 103 123 ' data-buttons-color="' . esc_attr( $button_color ) . '"' . … … 140 160 $responsive_to_view = isset( $attrs['frblResponsiveToView'] ) ? (int) $attrs['frblResponsiveToView'] : 1; 141 161 $autoplay = isset( $attrs['frblAutoplay'] ) ? ( (int) $attrs['frblAutoplay'] * 1000 ) : ''; 162 $gap = isset( $attrs['frblGap'] ) && '' !== $attrs['frblGap'] ? (int) $attrs['frblGap'] : 20; 142 163 $rewind = isset( $attrs['frblRewind'] ) ? (bool) $attrs['frblRewind'] : true; 143 164 $buttons = isset( $attrs['frblButtons'] ) ? sanitize_text_field( $attrs['frblButtons'] ) : 'arrows'; … … 164 185 ' data-mobile-view="' . esc_attr( $responsive_to_view ) . '"' . 165 186 ' data-autoplay="' . esc_attr( $autoplay ) . '"' . 187 ' data-gap="' . esc_attr( $gap ) . '"' . 166 188 ' data-buttons="' . esc_attr( $buttons ) . '"' . 167 189 ' data-buttons-color="' . esc_attr( $button_color ) . '"' . … … 204 226 $responsive_to_view = isset( $attrs['frblResponsiveToView'] ) ? (int) $attrs['frblResponsiveToView'] : 1; 205 227 $autoplay = isset( $attrs['frblAutoplay'] ) ? ( (int) $attrs['frblAutoplay'] * 1000 ) : ''; 228 $gap = isset( $attrs['frblGap'] ) && '' !== $attrs['frblGap'] ? (int) $attrs['frblGap'] : 20; 206 229 $rewind = isset( $attrs['frblRewind'] ) ? (bool) $attrs['frblRewind'] : true; 207 230 $buttons = isset( $attrs['frblButtons'] ) ? sanitize_text_field( $attrs['frblButtons'] ) : 'arrows'; … … 228 251 ' data-mobile-view="' . esc_attr( $responsive_to_view ) . '"' . 229 252 ' data-autoplay="' . esc_attr( $autoplay ) . '"' . 253 ' data-gap="' . esc_attr( $gap ) . '"' . 230 254 ' data-buttons="' . esc_attr( $buttons ) . '"' . 231 255 ' data-buttons-color="' . esc_attr( $button_color ) . '"' . … … 299 323 'type' => 'string', 300 324 'default' => '', 325 ); 326 $block_args['attributes']['frblGap'] = array( 327 'type' => 'string', 328 'default' => '20', 301 329 ); 302 330 $block_args['attributes']['frblRewind'] = array( … … 371 399 default: '' 372 400 }, 401 frblGap: { 402 type: 'string', 403 default: '20' 404 }, 373 405 frblButtons: { 374 406 type: 'string', -
frontblocks/tags/1.3.3/readme.txt
r3462660 r3472405 1 === FrontBlocks for Gutenberg andGeneratePress ===1 === FrontBlocks for Gutenberg/GeneratePress === 2 2 Contributors: davidperez, sacrajaimez, alexbreagarcia, matiasquero, amulero, mit2sumit, alexcm13 3 3 Tags: carrusel, slider, lightweight, generatepress, gutenberg 4 4 Donate link: https://close.marketing/go/donate/ 5 5 Requires at least: 5.0 6 Tested up to: 6.97 Stable tag: 1.3. 28 Version: 1.3. 26 Tested up to: 7.0 7 Stable tag: 1.3.3 8 Version: 1.3.3 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html 11 11 12 This plugin extends the functionality of GeneratePress by adding a carousel, slider, animations, sticky columns, edge alignment for containers and the ability to insert posts.12 Plugin extending Gutenberg and GeneratePress with carousel, slider, animations, sticky columns, edge alignment and post insertion capabilities. 13 13 14 14 == Description == … … 153 153 154 154 == Changelog == 155 156 == 1.3.3 == 157 * Fixed: Carousel bullets display and behavior. 158 * Fixed: Carousel editor styling and functionality. 159 * Fixed: Carousel in native (core) blocks. 160 * Fixed: Carousel JavaScript and CSS issues. 161 * Fixed: Stacked images block display. 162 * Fixed: Accordion in Gravity Forms inline layout. 163 * Improved: Carousel styles - updated classes and removed unnecessary declarations. 164 * Improved: Settings page and carousel advanced options. 165 * Improved: Shape animations option component. 166 * Improved: PHPStan compliance and code quality. 155 167 156 168 == 1.3.2 == -
frontblocks/tags/1.3.3/vendor/composer/installed.php
r3462660 r3472405 2 2 'root' => array( 3 3 'name' => 'close/frontblocks', 4 'pretty_version' => '1.3. 2',5 'version' => '1.3. 2.0',6 'reference' => ' 95247c40e9617d1fb79fb93f1daf791fb7e918db',4 'pretty_version' => '1.3.3', 5 'version' => '1.3.3.0', 6 'reference' => '7fb5a8fa3abcff0754a417193682455d7af5dc2d', 7 7 'type' => 'library', 8 8 'install_path' => __DIR__ . '/../../', … … 12 12 'versions' => array( 13 13 'close/frontblocks' => array( 14 'pretty_version' => '1.3. 2',15 'version' => '1.3. 2.0',16 'reference' => ' 95247c40e9617d1fb79fb93f1daf791fb7e918db',14 'pretty_version' => '1.3.3', 15 'version' => '1.3.3.0', 16 'reference' => '7fb5a8fa3abcff0754a417193682455d7af5dc2d', 17 17 'type' => 'library', 18 18 'install_path' => __DIR__ . '/../../', -
frontblocks/trunk/assets/admin/settings.css
r3462660 r3472405 521 521 margin-left: -0.25rem; 522 522 } 523 .frbl-settings-wrapper .tw-mb-0 { 524 margin-bottom: 0px; 525 } 523 526 .frbl-settings-wrapper .tw-mb-2 { 524 527 margin-bottom: 0.5rem; … … 530 533 margin-bottom: 2rem; 531 534 } 532 .frbl-settings-wrapper .tw-ml-2 {533 margin-left: 0.5rem;534 }535 535 .frbl-settings-wrapper .tw-ml-3 { 536 536 margin-left: 0.75rem; 537 537 } 538 .frbl-settings-wrapper .tw-ml-auto {539 margin-left: auto;540 }541 538 .frbl-settings-wrapper .tw-mr-2 { 542 539 margin-right: 0.5rem; 543 540 } 544 .frbl-settings-wrapper .tw-mt- 1{545 margin-top: 0 .25rem;541 .frbl-settings-wrapper .tw-mt-0 { 542 margin-top: 0px; 546 543 } 547 544 .frbl-settings-wrapper .tw-mt-2 { 548 545 margin-top: 0.5rem; 549 546 } 547 .frbl-settings-wrapper .tw-mt-4 { 548 margin-top: 1rem; 549 } 550 .frbl-settings-wrapper .tw-mt-6 { 551 margin-top: 1.5rem; 552 } 550 553 .frbl-settings-wrapper .tw-mt-8 { 551 554 margin-top: 2rem; … … 575 578 max-width: 64rem; 576 579 } 580 .frbl-settings-wrapper .tw-flex-1 { 581 flex: 1 1 0%; 582 } 577 583 .frbl-settings-wrapper .tw-flex-shrink-0 { 578 584 flex-shrink: 0; 579 585 } 580 .frbl-settings-wrapper .tw-flex-grow {581 flex-grow: 1;582 }583 .frbl-settings-wrapper .tw-items-start {584 align-items: flex-start;585 }586 586 .frbl-settings-wrapper .tw-items-center { 587 587 align-items: center; … … 592 592 .frbl-settings-wrapper .tw-gap-2 { 593 593 gap: 0.5rem; 594 }595 .frbl-settings-wrapper .tw-gap-3 {596 gap: 0.75rem;597 594 } 598 595 .frbl-settings-wrapper :is(.tw-space-x-2 > :not([hidden]) ~ :not([hidden])) { … … 601 598 margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); 602 599 } 603 .frbl-settings-wrapper :is(.tw-space-y-4 > :not([hidden]) ~ :not([hidden])) {604 --tw-space-y-reverse: 0;605 margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));606 margin-bottom: calc(1rem * var(--tw-space-y-reverse));607 }608 600 .frbl-settings-wrapper :is(.tw-space-y-6 > :not([hidden]) ~ :not([hidden])) { 609 601 --tw-space-y-reverse: 0; … … 611 603 margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); 612 604 } 605 .frbl-settings-wrapper .tw-overflow-auto { 606 overflow: auto; 607 } 613 608 .frbl-settings-wrapper .tw-overflow-hidden { 614 609 overflow: hidden; … … 647 642 border-color: rgb(209 213 219 / var(--tw-border-opacity, 1)); 648 643 } 649 .frbl-settings-wrapper .tw-border-green-300 {650 --tw-border-opacity: 1;651 border-color: rgb(134 239 172 / var(--tw-border-opacity, 1));652 }653 644 .frbl-settings-wrapper .tw-border-red-200 { 654 645 --tw-border-opacity: 1; 655 646 border-color: rgb(254 202 202 / var(--tw-border-opacity, 1)); 656 647 } 657 .frbl-settings-wrapper .tw-border-red-300 {658 --tw-border-opacity: 1;659 border-color: rgb(252 165 165 / var(--tw-border-opacity, 1));660 }661 648 .frbl-settings-wrapper .tw-border-transparent { 662 649 border-color: transparent; 663 650 } 664 .frbl-settings-wrapper .tw-border-yellow- 300 {651 .frbl-settings-wrapper .tw-border-yellow-200 { 665 652 --tw-border-opacity: 1; 666 border-color: rgb(25 3 224 71/ var(--tw-border-opacity, 1));653 border-color: rgb(254 240 138 / var(--tw-border-opacity, 1)); 667 654 } 668 655 .frbl-settings-wrapper .tw-border-yellow-400 { … … 678 665 background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1)); 679 666 } 680 .frbl-settings-wrapper .tw-bg-green-100 {681 --tw-bg-opacity: 1;682 background-color: rgb(220 252 231 / var(--tw-bg-opacity, 1));683 }684 667 .frbl-settings-wrapper .tw-bg-primary-100 { 685 668 --tw-bg-opacity: 1; … … 690 673 background-color: rgb(104 125 249 / var(--tw-bg-opacity, 1)); 691 674 } 692 .frbl-settings-wrapper .tw-bg-red-100 {693 --tw-bg-opacity: 1;694 background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1));695 }696 675 .frbl-settings-wrapper .tw-bg-red-50 { 697 676 --tw-bg-opacity: 1; … … 701 680 --tw-bg-opacity: 1; 702 681 background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); 703 }704 .frbl-settings-wrapper .tw-bg-yellow-100 {705 --tw-bg-opacity: 1;706 background-color: rgb(254 249 195 / var(--tw-bg-opacity, 1));707 682 } 708 683 .frbl-settings-wrapper .tw-bg-yellow-50 { … … 721 696 --tw-gradient-to: #fff var(--tw-gradient-to-position); 722 697 } 723 .frbl-settings-wrapper .tw-p-3 {724 padding: 0.75rem;725 }726 698 .frbl-settings-wrapper .tw-p-4 { 727 699 padding: 1rem; 700 } 701 .frbl-settings-wrapper .tw-p-6 { 702 padding: 1.5rem; 728 703 } 729 704 .frbl-settings-wrapper .tw-px-3 { … … 743 718 padding-bottom: 0.25rem; 744 719 } 720 .frbl-settings-wrapper .tw-py-2 { 721 padding-top: 0.5rem; 722 padding-bottom: 0.5rem; 723 } 745 724 .frbl-settings-wrapper .tw-py-3 { 746 725 padding-top: 0.75rem; … … 755 734 padding-bottom: 2rem; 756 735 } 757 .frbl-settings-wrapper .tw-pr-4 {758 padding-right: 1rem;759 }760 736 .frbl-settings-wrapper .tw-pt-6 { 761 737 padding-top: 1.5rem; … … 763 739 .frbl-settings-wrapper .tw-text-center { 764 740 text-align: center; 741 } 742 .frbl-settings-wrapper .tw-text-2xl { 743 font-size: 1.5rem; 744 line-height: 2rem; 765 745 } 766 746 .frbl-settings-wrapper .tw-text-3xl { … … 772 752 line-height: 1.5rem; 773 753 } 754 .frbl-settings-wrapper .tw-text-lg { 755 font-size: 1.125rem; 756 line-height: 1.75rem; 757 } 774 758 .frbl-settings-wrapper .tw-text-sm { 775 759 font-size: 0.875rem; … … 809 793 color: rgb(75 85 99 / var(--tw-text-opacity, 1)); 810 794 } 795 .frbl-settings-wrapper .tw-text-gray-700 { 796 --tw-text-opacity: 1; 797 color: rgb(55 65 81 / var(--tw-text-opacity, 1)); 798 } 811 799 .frbl-settings-wrapper .tw-text-gray-900 { 812 800 --tw-text-opacity: 1; 813 801 color: rgb(17 24 39 / var(--tw-text-opacity, 1)); 814 802 } 815 .frbl-settings-wrapper .tw-text-green-800 {816 --tw-text-opacity: 1;817 color: rgb(22 101 52 / var(--tw-text-opacity, 1));818 }819 803 .frbl-settings-wrapper .tw-text-primary-500 { 820 804 --tw-text-opacity: 1; … … 829 813 color: rgb(185 28 28 / var(--tw-text-opacity, 1)); 830 814 } 831 .frbl-settings-wrapper .tw-text-red-800 {832 --tw-text-opacity: 1;833 color: rgb(153 27 27 / var(--tw-text-opacity, 1));834 }835 815 .frbl-settings-wrapper .tw-text-white { 836 816 --tw-text-opacity: 1; … … 844 824 --tw-text-opacity: 1; 845 825 color: rgb(161 98 7 / var(--tw-text-opacity, 1)); 846 }847 .frbl-settings-wrapper .tw-text-yellow-800 {848 --tw-text-opacity: 1;849 color: rgb(133 77 14 / var(--tw-text-opacity, 1));850 826 } 851 827 .frbl-settings-wrapper .tw-underline { 852 828 text-decoration-line: underline; 853 }854 .frbl-settings-wrapper .tw-no-underline {855 text-decoration-line: none;856 }857 .frbl-settings-wrapper .tw-opacity-50 {858 opacity: 0.5;859 829 } 860 830 .frbl-settings-wrapper .tw-shadow-sm { … … 1052 1022 } 1053 1023 } 1054 .frbl-settings-wrapper .hover\:tw-bg-primary-200:hover {1055 --tw-bg-opacity: 1;1056 background-color: rgb(205 208 251 / var(--tw-bg-opacity, 1));1057 }1058 1024 .frbl-settings-wrapper .hover\:tw-bg-primary-600:hover { 1059 1025 --tw-bg-opacity: 1; … … 1063 1029 --tw-text-opacity: 1; 1064 1030 color: rgb(85 101 237 / var(--tw-text-opacity, 1)); 1065 }1066 .frbl-settings-wrapper .hover\:tw-no-underline:hover {1067 text-decoration-line: none;1068 1031 } 1069 1032 .frbl-settings-wrapper .focus\:tw-border-transparent:focus { … … 1101 1064 } 1102 1065 1103 /* Custom styles for license fields */1104 .frbl-settings-wrapper .tw-text-base:not(button) {1105 font-size: 1rem;1106 line-height: 1.5rem;1107 width: 100%;1108 }1109 1110 .frbl-settings-wrapper .tw-flex {1111 display: flex;1112 column-gap: 20px;1113 }1114 1115 /* Submit button width */1116 .frbl-settings-wrapper .tw-w-1\/2 {1117 width: 50%;1118 }1119 1120 /* Features Grid Layout */1121 .frbl-section-wrapper {1122 margin-bottom: 3rem;1123 }1124 1125 .frbl-features-grid {1126 display: grid;1127 grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));1128 gap: 1.25rem;1129 }1130 1131 /* Feature Card Styles */1132 .frbl-feature-card {1133 position: relative;1134 background: #ffffff;1135 border: 1px solid #e5e7eb;1136 border-radius: 12px;1137 padding: 1.5rem;1138 transition: all 0.2s ease;1139 overflow: hidden;1140 display: flex;1141 flex-direction: column;1142 min-height: 80px;1143 }1144 1145 .frbl-feature-card:hover {1146 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);1147 transform: translateY(-2px);1148 border-color: #687df9;1149 }1150 1151 /* PRO Badge */1152 .frbl-pro-badge {1153 position: absolute;1154 top: 0;1155 left: 0;1156 background: linear-gradient(135deg, #ec4899 0%, #f97316 100%);1157 color: #ffffff;1158 font-size: 0.625rem;1159 font-weight: 700;1160 letter-spacing: 0.05em;1161 padding: 0.25rem 0.75rem;1162 border-radius: 0 0 12px 0;1163 box-shadow: 0 2px 4px rgba(236, 72, 153, 0.3);1164 z-index: 10;1165 }1166 1167 /* Feature Card Content */1168 .frbl-feature-content {1169 display: flex;1170 align-items: center;1171 justify-content: space-between;1172 gap: 1rem;1173 min-height: 3rem;1174 }1175 1176 /* Feature Icon */1177 .frbl-feature-icon {1178 flex-shrink: 0;1179 width: 2.5rem;1180 height: 2.5rem;1181 display: flex;1182 align-items: center;1183 justify-content: center;1184 background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);1185 border-radius: 10px;1186 color: #687df9;1187 transition: all 0.2s ease;1188 }1189 1190 .frbl-feature-card:hover .frbl-feature-icon {1191 background: linear-gradient(135deg, #e0e3fc 0%, #d0d4fb 100%);1192 transform: scale(1.05);1193 }1194 1195 .frbl-feature-icon svg {1196 width: 1.5rem;1197 height: 1.5rem;1198 stroke-width: 2;1199 }1200 1201 /* Feature Info */1202 .frbl-feature-info {1203 flex: 1;1204 min-width: 0;1205 display: flex;1206 align-items: center;1207 }1208 1209 .frbl-feature-title {1210 font-size: 0.9375rem;1211 font-weight: 600;1212 color: #1f2937;1213 margin: 0;1214 line-height: 1.5;1215 }1216 1217 .frbl-feature-description {1218 font-size: 0.8125rem;1219 color: #6b7280;1220 margin: 0.25rem 0 0 0;1221 line-height: 1.4;1222 }1223 1224 /* Active Feature Cards */1225 .frbl-feature-card.frbl-feature-active {1226 background: linear-gradient(135deg, #ffffff 0%, #f0fdf4 100%);1227 border-color: #d1fae5;1228 }1229 1230 .frbl-feature-card.frbl-feature-active:hover {1231 border-color: #10b981;1232 }1233 1234 .frbl-feature-card.frbl-feature-active .frbl-feature-icon {1235 background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);1236 color: #10b981;1237 }1238 1239 .frbl-feature-card.frbl-feature-active:hover .frbl-feature-icon {1240 background: linear-gradient(135deg, #a7f3d0 0%, #6ee7b7 100%);1241 }1242 1243 /* Active cards need vertical layout for description */1244 .frbl-feature-card.frbl-feature-active .frbl-feature-info {1245 flex-direction: column;1246 align-items: flex-start;1247 }1248 1249 /* Active cards don't have toggle, so don't use space-between */1250 .frbl-feature-card.frbl-feature-active .frbl-feature-content {1251 justify-content: flex-start;1252 }1253 1254 /* Feature Toggle */1255 .frbl-feature-toggle {1256 flex-shrink: 0;1257 display: flex;1258 align-items: center;1259 }1260 1261 /* PRO Card Styles */1262 .frbl-feature-card.frbl-feature-pro {1263 background: linear-gradient(135deg, #ffffff 0%, #fef3f2 100%);1264 border-color: #fee2e2;1265 }1266 1267 .frbl-feature-card.frbl-feature-pro:hover {1268 border-color: #ec4899;1269 }1270 1271 .frbl-feature-card.frbl-feature-pro .frbl-feature-icon {1272 background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);1273 color: #ec4899;1274 }1275 1276 .frbl-feature-card.frbl-feature-pro:hover .frbl-feature-icon {1277 background: linear-gradient(135deg, #fecaca 0%, #fca5a5 100%);1278 }1279 1280 /* Disabled state for PRO features without license */1281 .frbl-feature-card.frbl-feature-pro .frbl-toggle:has(input:disabled) {1282 opacity: 0.6;1283 }1284 1285 /* Responsive adjustments */1286 @media (max-width: 768px) {1287 .frbl-features-grid {1288 grid-template-columns: 1fr;1289 }1290 1291 .frbl-feature-card {1292 padding: 1.25rem;1293 }1294 }1295 1296 @media (min-width: 768px) and (max-width: 1024px) {1297 .frbl-features-grid {1298 grid-template-columns: repeat(2, 1fr);1299 }1300 }1301 1302 1303 /* =============================================1304 License Management Styles (Complete & Independent)1305 Based on FormsCRM but standalone for FrontBlocks1306 ============================================= */1307 1308 /* License Wrapper - Grid Layout */1309 .formscrm-license-wrapper {1310 display: grid;1311 grid-template-columns: 1fr 320px;1312 gap: 24px;1313 max-width: 1200px;1314 margin: 20px 0;1315 }1316 1317 @media (max-width: 900px) {1318 .formscrm-license-wrapper {1319 grid-template-columns: 1fr;1320 }1321 }1322 1323 /* Main Card */1324 .formscrm-card {1325 background: #fff;1326 border: 1px solid #e5e7eb;1327 border-radius: 12px;1328 padding: 32px;1329 box-shadow: 0 1px 3px rgba(0,0,0,0.05);1330 }1331 1332 .formscrm-card-header {1333 margin-bottom: 24px;1334 padding-bottom: 20px;1335 border-bottom: 1px solid #e5e7eb;1336 }1337 1338 .formscrm-card-header h2 {1339 margin: 0 0 8px 0;1340 font-size: 1.5rem;1341 font-weight: 600;1342 color: #1f2937;1343 }1344 1345 .formscrm-card-header p {1346 margin: 0;1347 color: #6b7280;1348 font-size: 0.875rem;1349 }1350 1351 /* Form Elements */1352 .formscrm-form-group {1353 margin-bottom: 24px;1354 }1355 1356 .formscrm-label {1357 display: block;1358 font-weight: 600;1359 color: #374151;1360 margin-bottom: 8px;1361 font-size: 0.875rem;1362 }1363 1364 .formscrm-input-group {1365 display: flex;1366 gap: 12px;1367 align-items: center;1368 }1369 1370 .formscrm-input {1371 flex: 1;1372 padding: 12px 16px;1373 border: 1px solid #d1d5db;1374 border-radius: 8px;1375 font-size: 1rem;1376 transition: all 0.2s;1377 background: #fff;1378 }1379 1380 .formscrm-input:focus {1381 outline: none;1382 border-color: #8b5cf6;1383 box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.15);1384 }1385 1386 .formscrm-input[readonly] {1387 background: #f9fafb;1388 color: #6b7280;1389 cursor: not-allowed;1390 }1391 1392 /* Deactivate Label */1393 .formscrm-deactivate-label {1394 display: flex;1395 align-items: center;1396 gap: 8px;1397 padding: 12px 16px;1398 background: #fef2f2;1399 border: 1px solid #fecaca;1400 border-radius: 8px;1401 cursor: pointer;1402 transition: background 0.2s;1403 white-space: nowrap;1404 }1405 1406 .formscrm-deactivate-label:hover {1407 background: #fee2e2;1408 }1409 1410 .formscrm-deactivate-label input {1411 margin: 0;1412 }1413 1414 .formscrm-deactivate-label span {1415 font-size: 0.875rem;1416 font-weight: 600;1417 color: #dc2626;1418 }1419 1420 /* Help Text */1421 .formscrm-help-text {1422 margin: 8px 0 0 0;1423 font-size: 0.75rem;1424 color: #9ca3af;1425 }1426 1427 /* Status Box */1428 .formscrm-status-box {1429 display: flex;1430 align-items: center;1431 gap: 12px;1432 padding: 14px 18px;1433 border-radius: 8px;1434 border: 2px solid;1435 }1436 1437 .formscrm-status-active {1438 background: #dcfce7;1439 border-color: #86efac;1440 color: #166534;1441 }1442 1443 .formscrm-status-expired {1444 background: #fee2e2;1445 border-color: #fca5a5;1446 color: #991b1b;1447 }1448 1449 .formscrm-status-inactive {1450 background: #fef9c3;1451 border-color: #fde047;1452 color: #854d0e;1453 }1454 1455 .formscrm-status-icon {1456 display: flex;1457 flex-shrink: 0;1458 }1459 1460 .formscrm-icon,1461 .fcod-icon {1462 width: 22px;1463 height: 22px;1464 }1465 1466 .formscrm-status-text {1467 font-weight: 700;1468 font-size: 1rem;1469 }1470 1471 /* Notices */1472 .formscrm-notice {1473 padding: 14px 18px;1474 border-radius: 8px;1475 margin-bottom: 20px;1476 }1477 1478 .formscrm-notice p {1479 margin: 0;1480 font-size: 0.875rem;1481 line-height: 1.5;1482 }1483 1484 .formscrm-notice a {1485 font-weight: 600;1486 text-decoration: underline;1487 }1488 1489 .formscrm-notice-info {1490 background: #f0f9ff;1491 border: 1px solid #bfdbfe;1492 color: #1e40af;1493 }1494 1495 .formscrm-notice-info a {1496 color: #1d4ed8;1497 }1498 1499 .formscrm-notice-error {1500 background: #fef2f2;1501 border: 1px solid #fecaca;1502 color: #991b1b;1503 }1504 1505 .formscrm-notice-error a {1506 color: #dc2626;1507 }1508 1509 /* Form Actions */1510 .formscrm-form-actions {1511 margin-top: 24px;1512 padding-top: 24px;1513 border-top: 1px solid #e5e7eb;1514 }1515 1516 /* Buttons - FrontBlocks Purple Style */1517 .formscrm-button {1518 display: inline-flex;1519 align-items: center;1520 padding: 12px 24px;1521 border-radius: 8px;1522 font-size: 1rem;1523 font-weight: 600;1524 cursor: pointer;1525 transition: all 0.2s;1526 border: none;1527 }1528 1529 .formscrm-button-primary {1530 background: #8b5cf6;1531 color: #fff;1532 }1533 1534 .formscrm-button-primary:hover {1535 background: #7c3aed;1536 box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);1537 }1538 1539 /* Info Card (Sidebar) */1540 .formscrm-info-card {1541 background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);1542 border: 1px solid #e2e8f0;1543 border-radius: 12px;1544 padding: 24px;1545 height: fit-content;1546 }1547 1548 .formscrm-info-card h3 {1549 margin: 0 0 12px 0;1550 font-size: 1.125rem;1551 font-weight: 700;1552 color: #1e293b;1553 }1554 1555 .formscrm-info-card p {1556 margin: 0 0 16px 0;1557 font-size: 0.875rem;1558 color: #64748b;1559 line-height: 1.5;1560 }1561 1562 /* Benefits List */1563 .formscrm-benefits-list {1564 margin: 0;1565 padding: 0;1566 list-style: none;1567 }1568 1569 .formscrm-benefits-list li {1570 position: relative;1571 padding-left: 28px;1572 margin-bottom: 10px;1573 font-size: 0.875rem;1574 color: #475569;1575 }1576 1577 .formscrm-benefits-list li::before {1578 content: "✓";1579 position: absolute;1580 left: 0;1581 top: 0;1582 color: #8b5cf6;1583 font-weight: 700;1584 font-size: 1.125rem;1585 } -
frontblocks/trunk/assets/carousel/frontblocks-advanced-option.js
r3462660 r3472405 1 1 "use strict"; 2 2 3 function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } 4 function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } 5 function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } 3 6 // Add custom controls to the Advanced panel of GenerateBlocks Grid block 4 7 var addFilter = wp.hooks.addFilter; 5 var Fragment = wp.element.Fragment; 8 var _wp$element = wp.element, 9 Fragment = _wp$element.Fragment, 10 useEffect = _wp$element.useEffect, 11 useRef = _wp$element.useRef; 6 12 var _wp$blockEditor = wp.blockEditor, 7 13 InspectorControls = _wp$blockEditor.InspectorControls, … … 13 19 ToggleControl = _wp$components.ToggleControl; 14 20 var __ = wp.i18n.__; 21 22 /** 23 * Returns the document that renders block content. 24 * WordPress 6.x uses an <iframe> for the editor canvas. 25 */ 26 function getEditorDocument() { 27 var iframe = document.querySelector('iframe[name="editor-canvas"]'); 28 return iframe && iframe.contentDocument && iframe.contentDocument.body ? iframe.contentDocument : document; 29 } 30 var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-/; 31 32 /** 33 * Walk an element's subtree to find the container whose DIRECT children 34 * are actual blocks (UUID data-block). Stops at depth 4. 35 */ 36 function findSlidesParent(el, depth) { 37 if (depth === 0) return null; 38 if (Array.from(el.children).some(function (c) { 39 return UUID_RE.test(c.dataset.block || ''); 40 })) { 41 return el; 42 } 43 var _iterator = _createForOfIteratorHelper(el.children), 44 _step; 45 try { 46 for (_iterator.s(); !(_step = _iterator.n()).done;) { 47 var child = _step.value; 48 var found = findSlidesParent(child, depth - 1); 49 if (found) return found; 50 } 51 } catch (err) { 52 _iterator.e(err); 53 } finally { 54 _iterator.f(); 55 } 56 return null; 57 } 58 59 /** 60 * Find the grid DOM element for a given block. 61 * 62 * For generateblocks/element: [data-block][data-type] IS the gb-element. 63 * Do NOT search inside – that returns a child item. 64 * For generateblocks/grid: look for .gb-grid-wrapper inside. 65 * For core/group: walk the subtree to find the element whose children 66 * are the real blocks, because WP nests them differently across versions. 67 */ 68 function findGridEl(blockEl, name) { 69 if (name === 'generateblocks/element') { 70 return blockEl; 71 } 72 if (name === 'generateblocks/grid') { 73 if (blockEl.classList.contains('gb-grid-wrapper')) return blockEl; 74 var grid = blockEl.querySelector('.gb-grid-wrapper'); 75 return grid || null; 76 } 77 if (name === 'core/group') { 78 // Walk up to 4 levels deep to find where the child blocks live. 79 return findSlidesParent(blockEl, 4) || blockEl; 80 } 81 return null; 82 } 15 83 function addCustomCarouselPanel(BlockEdit) { 16 84 return function (props) { 17 // Support grid blocks, element blocks with grid display, and core/group blocks18 85 if (props.name !== 'generateblocks/grid' && props.name !== 'generateblocks/element' && props.name !== 'core/group') { 19 86 return /*#__PURE__*/React.createElement(BlockEdit, props); 20 87 } 21 22 // For element blocks, only show carousel options if it has grid display23 88 if (props.name === 'generateblocks/element') { 24 89 var styles = props.attributes.styles || {}; … … 27 92 } 28 93 } 29 30 // For core/group blocks, only show carousel options if it has grid layout31 94 if (props.name === 'core/group') { 32 95 var layout = props.attributes.layout || {}; … … 48 111 _props$attributes$frb6 = _props$attributes.frblAutoplay, 49 112 frblAutoplay = _props$attributes$frb6 === void 0 ? '' : _props$attributes$frb6, 50 _props$attributes$frb7 = _props$attributes.frblButtons, 51 frblButtons = _props$attributes$frb7 === void 0 ? 'arrows' : _props$attributes$frb7, 52 _props$attributes$frb8 = _props$attributes.frblRewind, 53 frblRewind = _props$attributes$frb8 === void 0 ? true : _props$attributes$frb8, 113 _props$attributes$frb7 = _props$attributes.frblGap, 114 frblGap = _props$attributes$frb7 === void 0 ? '20' : _props$attributes$frb7, 115 _props$attributes$frb8 = _props$attributes.frblButtons, 116 frblButtons = _props$attributes$frb8 === void 0 ? 'arrows' : _props$attributes$frb8, 117 _props$attributes$frb9 = _props$attributes.frblRewind, 118 frblRewind = _props$attributes$frb9 === void 0 ? true : _props$attributes$frb9, 54 119 frblButtonColor = _props$attributes.frblButtonColor, 55 120 frblButtonBgColor = _props$attributes.frblButtonBgColor, 56 _props$attributes$frb9 = _props$attributes.frblButtonsPosition, 57 frblButtonsPosition = _props$attributes$frb9 === void 0 ? 'side' : _props$attributes$frb9, 58 _props$attributes$frb0 = _props$attributes.frblDisableOnDesktop, 59 frblDisableOnDesktop = _props$attributes$frb0 === void 0 ? false : _props$attributes$frb0; 121 _props$attributes$frb0 = _props$attributes.frblButtonsPosition, 122 frblButtonsPosition = _props$attributes$frb0 === void 0 ? 'side' : _props$attributes$frb0, 123 _props$attributes$frb1 = _props$attributes.frblDisableOnDesktop, 124 frblDisableOnDesktop = _props$attributes$frb1 === void 0 ? false : _props$attributes$frb1; 125 126 // ── Editor carousel preview ────────────────────────────────────────── 127 var stateRef = useRef(null); 128 useEffect(function () { 129 var mounted = true; 130 var timer = null; 131 function cleanup() { 132 if (!stateRef.current) return; 133 var _stateRef$current = stateRef.current, 134 gridEl = _stateRef$current.gridEl, 135 slides = _stateRef$current.slides, 136 spacer = _stateRef$current.spacer, 137 prevBtn = _stateRef$current.prevBtn, 138 nextBtn = _stateRef$current.nextBtn, 139 resizeObs = _stateRef$current.resizeObs, 140 scrollFn = _stateRef$current.scrollFn; 141 142 // Disconnect observer and scroll listener. 143 if (resizeObs) resizeObs.disconnect(); 144 var editorDoc = getEditorDocument(); 145 var editorScrollEl = editorDoc.documentElement || editorDoc.body; 146 if (scrollFn) editorScrollEl.removeEventListener('scroll', scrollFn, true); 147 148 // Remove arrows from outer window body (completely outside React). 149 [prevBtn, nextBtn].forEach(function (btn) { 150 if (btn && btn.parentNode) btn.parentNode.removeChild(btn); 151 }); 152 153 // Remove right spacer element. 154 if (spacer && spacer.parentNode) spacer.parentNode.removeChild(spacer); 155 156 // Restore gridEl styles. 157 try { 158 gridEl.classList.remove('frbl-carousel-noscrollbar'); 159 ['display', 'flex-wrap', 'gap', 'overflow-x', 'scroll-behavior', 'padding-left', 'padding-right'].forEach(function (p) { 160 return gridEl.style.removeProperty(p); 161 }); 162 slides.forEach(function (slide) { 163 ['flex-shrink', 'width', 'min-width', 'margin-left', 'margin-right', 'grid-column'].forEach(function (p) { 164 return slide.style.removeProperty(p); 165 }); 166 }); 167 } catch (e) {} 168 stateRef.current = null; 169 } 170 function init() { 171 if (!mounted) return; 172 cleanup(); 173 var editorDoc = getEditorDocument(); 174 175 // GB 2.x wraps blocks in a root element that shares the same data-block UUID. 176 // Use data-type to select the correct inner element; fall back for native blocks. 177 var blockEl = editorDoc.querySelector("[data-block=\"".concat(props.clientId, "\"][data-type=\"").concat(props.name, "\"]")); 178 if (!blockEl) { 179 blockEl = editorDoc.querySelector("[data-block=\"".concat(props.clientId, "\"]")); 180 } 181 if (!blockEl) return; 182 var gridEl = findGridEl(blockEl, props.name); 183 if (!gridEl) return; 184 185 // Slides = direct children that are real blocks (UUID data-block). 186 var slides = Array.from(gridEl.children).filter(function (el) { 187 return UUID_RE.test(el.dataset.block || ''); 188 }); 189 if (slides.length === 0) return; 190 var perView = Math.max(1, parseInt(frblItemsToView) || 4); 191 var gap = Math.max(0, parseInt(frblGap) || 20); 192 var btnColor = frblButtonColor || '#fff'; 193 var btnBg = frblButtonBgColor || 'rgba(0,0,0,0.45)'; 194 195 // Measure content-box width before any style changes. 196 var editorWin = editorDoc.defaultView || window; 197 var ARROW_W = 40; // px reserved on each side for arrow buttons. 198 var cs = editorWin.getComputedStyle(gridEl); 199 var innerW = gridEl.getBoundingClientRect().width - (parseFloat(cs.paddingLeft) || 0) - (parseFloat(cs.paddingRight) || 0); 200 var totalWidth = Math.round(innerW) || 600; 201 // Content area after reserving space for both arrow buttons. 202 var contentW = totalWidth - ARROW_W * 2; 203 var slideWidth = Math.round((contentW - gap * (perView - 1)) / perView); 204 var step = slideWidth + gap; 205 206 // ── Apply scroll-based layout directly to gridEl ───────────── 207 // No DOM restructuring → no React reconciliation conflicts. 208 gridEl.classList.add('frbl-carousel-noscrollbar'); 209 gridEl.style.display = 'flex'; 210 gridEl.style.flexWrap = 'nowrap'; 211 gridEl.style.gap = gap + 'px'; 212 gridEl.style.overflowX = 'scroll'; 213 gridEl.style.scrollBehavior = 'smooth'; 214 // paddingLeft creates left space for the prev arrow. 215 // paddingRight is NOT used because Chrome ignores it in scroll extent; 216 // a spacer flex child is appended instead to guarantee right-side space. 217 gridEl.style.paddingLeft = ARROW_W + 'px'; 218 gridEl.style.paddingRight = '0'; 219 slides.forEach(function (slide) { 220 slide.style.flexShrink = '0'; 221 slide.style.width = slideWidth + 'px'; 222 slide.style.minWidth = slideWidth + 'px'; 223 slide.style.marginLeft = '0'; 224 slide.style.marginRight = '0'; 225 slide.style.gridColumn = 'unset'; 226 }); 227 228 // Right-side spacer: Chrome does not include padding-right in horizontal 229 // scroll extent, so we use a real flex child to guarantee right space. 230 var appender = gridEl.querySelector('.block-list-appender'); 231 var spacer = editorDoc.createElement('span'); 232 spacer.setAttribute('data-frbl-spacer', '1'); 233 spacer.style.cssText = "display:block;flex-shrink:0;width:".concat(ARROW_W, "px;min-width:").concat(ARROW_W, "px;"); 234 gridEl.insertBefore(spacer, appender || null); 235 236 // ── Navigation (scrollLeft, infinite loop) ─────────────────── 237 var idx = 0; 238 function scrollTo(n) { 239 var total = slides.length; 240 if (n >= total) { 241 // Forward past last: instant snap to 0 then continue. 242 gridEl.style.scrollBehavior = 'auto'; 243 gridEl.scrollLeft = 0; 244 void gridEl.offsetWidth; 245 gridEl.style.scrollBehavior = 'smooth'; 246 idx = 0; 247 return; 248 } 249 if (n < 0) { 250 // Back past first: instant snap to last. 251 gridEl.style.scrollBehavior = 'auto'; 252 gridEl.scrollLeft = Math.round((total - 1) * step); 253 void gridEl.offsetWidth; 254 gridEl.style.scrollBehavior = 'smooth'; 255 idx = total - 1; 256 return; 257 } 258 idx = n; 259 gridEl.scrollLeft = Math.round(idx * step); 260 } 261 262 // ── Arrows in OUTER document body ──────────────────────────── 263 // Placing them outside the iframe means React never touches them. 264 var iframe = document.querySelector('iframe[name="editor-canvas"]'); 265 function updateArrowPos() { 266 if (!stateRef.current) return; 267 var ifrRect = iframe ? iframe.getBoundingClientRect() : { 268 top: 0, 269 left: 0 270 }; 271 var rect = gridEl.getBoundingClientRect(); // coords in iframe viewport 272 var midY = Math.round(ifrRect.top + rect.top + rect.height / 2 - 16); 273 prevBtn.style.top = midY + 'px'; 274 prevBtn.style.left = Math.round(ifrRect.left + rect.left + 8) + 'px'; 275 nextBtn.style.top = midY + 'px'; 276 nextBtn.style.right = Math.round(window.innerWidth - (ifrRect.left + rect.right) + 8) + 'px'; 277 } 278 function makeArrow(dir) { 279 var btn = document.createElement('button'); 280 btn.type = 'button'; 281 btn.className = "frbl-editor-arrow frbl-editor-arrow-".concat(dir); 282 btn.setAttribute('aria-label', dir === 'prev' ? 'Previous slide' : 'Next slide'); 283 btn.style.cssText = "position:fixed;z-index:99999;background-color:".concat(btnBg, ";"); 284 var d = dir === 'prev' ? 'M6 1L1 6L6 11' : 'M1 11L6 6L1 1'; 285 btn.innerHTML = "<svg width=\"7\" height=\"12\" viewBox=\"0 0 7 12\" fill=\"none\"><path d=\"".concat(d, "\" stroke=\"").concat(btnColor, "\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>"); 286 btn.addEventListener('click', function (e) { 287 e.stopPropagation(); 288 scrollTo(dir === 'prev' ? idx - 1 : idx + 1); 289 }); 290 document.body.appendChild(btn); 291 return btn; 292 } 293 var prevBtn = makeArrow('prev'); 294 var nextBtn = makeArrow('next'); 295 updateArrowPos(); 296 297 // Keep arrows positioned correctly when the editor scrolls or resizes. 298 var resizeObs = new ResizeObserver(updateArrowPos); 299 resizeObs.observe(gridEl); 300 var editorScrollEl = editorDoc.documentElement || editorDoc.body; 301 var scrollFn = updateArrowPos; 302 editorScrollEl.addEventListener('scroll', scrollFn, { 303 passive: true, 304 capture: true 305 }); 306 stateRef.current = { 307 gridEl: gridEl, 308 slides: slides, 309 spacer: spacer, 310 prevBtn: prevBtn, 311 nextBtn: nextBtn, 312 resizeObs: resizeObs, 313 scrollFn: scrollFn 314 }; 315 } 316 if (frblGridOption !== 'none') { 317 timer = setTimeout(init, 300); 318 } else { 319 cleanup(); 320 } 321 return function () { 322 mounted = false; 323 if (timer) clearTimeout(timer); 324 cleanup(); 325 }; 326 }, [frblGridOption, frblItemsToView, frblGap, frblButtonColor, frblButtonBgColor, props.clientId]); 327 // ── Inspector panel ────────────────────────────────────────────────── 328 60 329 return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockEdit, props), /*#__PURE__*/React.createElement(InspectorControls, null, /*#__PURE__*/React.createElement(PanelBody, { 61 330 title: __('Carousel Settings', 'frontblocks'), … … 75 344 }], 76 345 onChange: function onChange(value) { 77 props.setAttributes({346 return props.setAttributes({ 78 347 frblGridOption: value 79 348 }); … … 124 393 }); 125 394 } 126 }), frblGridOption === 'slider' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ToggleControl, { 395 }), /*#__PURE__*/React.createElement(TextControl, { 396 label: __('Gap (px)', 'frontblocks'), 397 value: frblGap, 398 onChange: function onChange(value) { 399 return props.setAttributes({ 400 frblGap: value 401 }); 402 }, 403 help: __('Space between slides in pixels. Leave empty for 20.', 'frontblocks') 404 }), frblGridOption === 'slider' && /*#__PURE__*/React.createElement(ToggleControl, { 127 405 label: __('Rewind', 'frontblocks'), 128 406 checked: frblRewind, … … 132 410 }); 133 411 } 134 }) ), /*#__PURE__*/React.createElement(SelectControl, {412 }), /*#__PURE__*/React.createElement(SelectControl, { 135 413 label: __('Buttons', 'frontblocks'), 136 414 value: frblButtons, … … 150 428 }); 151 429 } 152 }), frblButtons === 'arrows' && /*#__PURE__*/React.createElement( React.Fragment, null, /*#__PURE__*/React.createElement(SelectControl, {430 }), frblButtons === 'arrows' && /*#__PURE__*/React.createElement(SelectControl, { 153 431 label: __('Buttons Position', 'frontblocks'), 154 432 value: frblButtonsPosition, … … 165 443 }); 166 444 } 167 }) ), /*#__PURE__*/React.createElement(PanelColorSettings, {445 }), /*#__PURE__*/React.createElement(PanelColorSettings, { 168 446 title: __('Button Colors', 'frontblocks'), 169 447 colorSettings: [{ -
frontblocks/trunk/assets/carousel/frontblocks-carousel.css
r3462660 r3472405 1 1 /** 2 * ## Glide Carousel style 3 * ---------------------------*/4 5 . glide {2 * Frontblocks Carousel – scoped under .frontblocks so other Glide instances are not affected. 3 */ 4 5 .frontblocks.glide { 6 6 position: relative; 7 7 width: 100%; 8 max-width: 100%; 8 9 box-sizing: border-box; 9 } 10 .glide * { 10 overflow: visible; 11 margin: 0; 12 padding: 0; 13 } 14 15 .frontblocks.glide * { 11 16 box-sizing: inherit; 12 17 } 13 .glide__track { 18 19 .frontblocks .glide__track { 14 20 overflow: hidden; 15 } 16 .glide__slides { 21 width: 100%; 22 position: relative; 23 left: 0; 24 margin: 0; 25 padding: 0; 26 } 27 28 .frontblocks .glide__slides { 17 29 position: relative; 18 30 width: 100%; … … 28 40 flex-wrap: nowrap; 29 41 will-change: transform; 30 transition: transform 400ms cubic-bezier(0.165, 0.84, 0.44, 1); 31 } 32 .glide__slides--dragging { 33 user-select: none; 34 } 35 .glide__slide { 42 } 43 44 .frontblocks .glide__slides--dragging { 45 user-select: none; 46 } 47 48 .frontblocks .glide__slide { 36 49 width: 100%; 37 50 height: 100%; … … 41 54 -webkit-touch-callout: none; 42 55 -webkit-tap-highlight-color: transparent; 43 } 44 .glide__slide a { 56 min-width: 0; 57 overflow: hidden; 58 } 59 60 /* Prevent inner content (cards, AWB, etc.) from overflowing the slide and being cut off. */ 61 .frontblocks .glide__slide > * { 62 max-width: 100%; 63 box-sizing: border-box; 64 } 65 66 .frontblocks .glide__slide a { 45 67 user-select: none; 46 68 -webkit-user-drag: none; … … 48 70 -ms-user-select: none; 49 71 } 50 .glide__arrows { 72 73 .frontblocks .glide__arrows { 51 74 -webkit-touch-callout: none; 52 75 user-select: none; 53 76 } 54 .glide__bullets { 77 78 .frontblocks .glide__bullets { 55 79 -webkit-touch-callout: none; 56 80 user-select: none; 57 81 } 58 .glide--rtl { 82 83 .frontblocks.glide--rtl { 59 84 direction: rtl; 60 85 } 61 86 62 /*# sourceMappingURL=glide.core.css.map */ 63 64 .glide__arrow { 87 .frontblocks .glide__arrow { 65 88 position: absolute; 66 89 display: block; … … 79 102 line-height: 1; 80 103 } 81 .glide__arrow:focus { 104 105 .frontblocks .glide__arrow:focus { 82 106 outline: none; 83 107 } 84 .glide__arrow:hover { 108 109 .frontblocks .glide__arrow:hover { 85 110 border-color: white; 86 111 } 87 .glide__arrow--left { 88 left: -1em; 89 } 90 .glide__arrow--right { 91 right: -1em; 92 } 93 .glide__arrow--disabled { 112 113 .frontblocks .glide__arrow--left { 114 left: 1em; 115 } 116 117 .frontblocks .glide__arrow--right { 118 right: 1em; 119 } 120 121 .frontblocks .glide__arrow--disabled { 94 122 opacity: 0.33; 95 123 } 96 .glide__bullets { 97 position: absolute; 98 z-index: 2; 99 bottom: -1em; 100 left: 50%; 101 display: inline-flex; 124 125 .frontblocks .glide__bullets { 126 display: flex; 127 justify-content: center; 102 128 list-style: none; 103 transform: translateX(-50%); 104 gap: 5px; 105 } 106 .glide__bullet { 107 background-color: rgba(255, 255, 255, 0.5); 108 width: 13px; 109 height: 13px; 129 gap: 2px; 130 margin: 0.75em 0 0; 131 padding: 0; 132 } 133 134 .frontblocks .glide__bullet { 135 box-sizing: content-box; 136 width: 10px; 137 height: 10px; 110 138 padding: 0; 111 139 border-radius: 50%; 112 border: 2px solid transparent;113 transition: all 300ms ease-in-out;140 border: none; 141 background-color: var(--frbl-bullet-bg, rgba(0, 0, 0, 0.25)); 114 142 cursor: pointer; 115 line-height: 0; 116 margin: 0; 117 } 118 .glide__bullet:focus { 119 outline: none; 120 } 121 .glide__bullet:hover, .glide__bullet:focus { 122 border: 2px solid white; 123 background-color: rgba(255, 255, 255, 0.5); 124 } 125 .glide__bullet--active { 126 background-color: white; 127 } 128 .glide--swipeable { 143 transition: background-color 300ms ease-in-out, transform 300ms ease-in-out; 144 margin: 0 2px; 145 flex-shrink: 0; 146 } 147 148 .frontblocks .glide__bullet:focus { 149 outline: 2px solid var(--frbl-bullet-color, rgba(0, 0, 0, 0.8)); 150 outline-offset: 2px; 151 } 152 153 .frontblocks .glide__bullet:hover { 154 background-color: var(--frbl-bullet-color, rgba(0, 0, 0, 0.8)); 155 transform: scale(1.2); 156 } 157 158 .frontblocks .glide__bullet--active { 159 background-color: var(--frbl-bullet-color, rgba(0, 0, 0, 0.8)); 160 transform: scale(1.2); 161 } 162 163 .frontblocks.glide--swipeable { 129 164 cursor: grab; 130 165 cursor: -moz-grab; 131 166 cursor: -webkit-grab; 132 167 } 133 .glide--dragging { 168 169 .frontblocks.glide--dragging { 134 170 cursor: grabbing; 135 171 cursor: -moz-grabbing; 136 172 cursor: -webkit-grabbing; 137 173 } 138 .glide__arrows--bottom .glide__arrow { 139 top: calc(100% + 25px); 140 left: 0; 141 } 142 .glide__arrows--bottom .glide__arrow--right { 143 left: 50px; 144 right: unset; 145 } 146 /* Arrows position top/side - spans full container width */ 147 .glide__arrows--top { 148 position: absolute; 149 top: 50%; 150 left: 0; 151 right: 0; 152 width: 100%; 153 z-index: 10; 154 pointer-events: none; 155 transform: translateY(-50%); 156 } 157 .glide__arrows--top .glide__arrow { 158 pointer-events: all; 159 } 160 .glide__arrows--top .glide__arrow--left { 161 left: 2em; 162 } 163 .glide__arrows--top .glide__arrow--right { 164 right: 2em; 165 } 166 /* Responsive */ 174 175 .frontblocks .glide__arrows--bottom .glide__arrow { 176 top: calc(100% + 25px); 177 left: 0; 178 } 179 180 .frontblocks .glide__arrows--bottom .glide__arrow--right { 181 left: 50px; 182 right: unset; 183 } 184 185 .frontblocks .glide__arrows--top { 186 position: absolute; 187 top: 50%; 188 left: 0; 189 right: 0; 190 width: 100%; 191 z-index: 10; 192 pointer-events: none; 193 transform: translateY(-50%); 194 } 195 196 .frontblocks .glide__arrows--top .glide__arrow { 197 pointer-events: all; 198 } 199 200 .frontblocks .glide__arrows--top .glide__arrow--left { 201 left: 2em; 202 } 203 204 .frontblocks .glide__arrows--top .glide__arrow--right { 205 right: 2em; 206 } 207 167 208 @media only screen and (max-width: 768px) { 168 .glide__arrow--left { 169 left: 0; 170 } 171 .glide__arrow--right { 172 right: 0; 173 } 174 } 175 176 /*# sourceMappingURL=glide.theme.css.map */ 209 .frontblocks .glide__arrow--left { 210 left: 0.5em; 211 } 212 .frontblocks .glide__arrow--right { 213 right: 0.5em; 214 } 215 } 177 216 178 217 /** 179 * Override native Gutenberg Grid styles when carousel is active 218 * Override native Gutenberg Grid styles when carousel is active (scoped to frontblocks carousel). 180 219 */ 181 220 .wp-block-group.frontblocks-carousel, 182 221 .wp-block-group.frontblocks-carousel.is-layout-grid { 183 display: block; 184 grid-template-columns: none; 185 gap: 0; 222 display: block; 223 grid-template-columns: none; 224 gap: 0; 225 } 226 227 .wp-block-group.frontblocks-carousel .frontblocks.glide, 228 .wp-block-group.frontblocks-carousel .frontblocks .glide__track { 229 width: 100%; 230 max-width: 100%; 231 margin-left: 0; 232 margin-right: 0; 233 padding-left: 0; 234 padding-right: 0; 186 235 } 187 236 188 237 .wp-block-group.frontblocks-carousel > * { 189 width: 100%; 190 } 191 192 /* Ensure inner container doesn't interfere with carousel */ 238 width: 100%; 239 } 240 193 241 .wp-block-group.frontblocks-carousel > .wp-block-group__inner-container { 194 display: block; 195 grid-template-columns: none; 196 gap: 0; 197 width: 100%; 198 } 199 200 /* Override grid styles for direct children in carousel mode */ 201 .glide__slides.wp-block-group, 202 .glide__slides.wp-block-group.is-layout-grid { 203 display: flex; 204 grid-template-columns: none; 205 gap: 0; 206 column-gap: 0; 207 row-gap: 0; 208 } 209 210 /* Ensure slides have proper width */ 211 .glide__slides > .glide__slide { 212 min-width: 0; 213 flex-shrink: 0; 214 } 215 216 /* Force full width for single slide view */ 217 .frontblocks-carousel[data-view="1"] .glide__slide { 218 margin-left: 0; 219 margin-right: 0; 220 } 221 222 /* Remove gaps when showing one slide */ 223 .frontblocks-carousel[data-view="1"].glide__slides { 224 gap: 0; 225 } 226 227 /* Responsive single slide view */ 228 @media only screen and (max-width: 768px) { 229 .frontblocks-carousel[data-mobile-view="1"] .glide__slide { 230 width: 100%; 231 flex: 0 0 100%; 232 max-width: 100%; 233 margin-left: 0; 234 margin-right: 0; 235 } 236 } 237 238 @media only screen and (min-width: 769px) and (max-width: 1024px) { 239 .frontblocks-carousel[data-tablet-view="1"] .glide__slide { 240 width: 100%; 241 flex: 0 0 100%; 242 max-width: 100%; 243 margin-left: 0; 244 margin-right: 0; 245 } 246 } 247 248 @media only screen and (min-width: 1025px) and (max-width: 1440px) { 249 .frontblocks-carousel[data-laptop-view="1"] .glide__slide { 250 width: 100%; 251 flex: 0 0 100%; 252 max-width: 100%; 253 margin-left: 0; 254 margin-right: 0; 255 } 256 } 257 258 /* Handle alignfull content within carousel slides */ 259 .glide__slide > .wp-block-cover.alignfull, 260 .glide__slide > .alignfull { 261 width: 100%; 262 max-width: none; 263 margin-left: 0; 264 margin-right: 0; 265 } 266 267 /* Ensure cover blocks maintain minimum height */ 268 .glide__slide .wp-block-cover { 269 min-height: 430px; 270 display: flex; 271 align-items: center; 272 justify-content: center; 273 } 274 275 /* Prevent carousel from overflowing viewport */ 276 .glide { 277 position: relative; 278 overflow: visible; 279 min-height: 430px; 280 } 281 282 .glide__track { 283 overflow: hidden; 284 width: 100%; 285 position: relative; 286 z-index: 1; 287 } 288 289 .glide__slides { 290 position: relative; 291 z-index: 1; 292 height: auto; 293 min-height: 430px; 294 } 295 296 .glide__slide { 297 position: relative; 298 z-index: 1; 299 height: auto; 300 opacity: 1; 301 visibility: visible; 302 } 242 display: block; 243 grid-template-columns: none; 244 gap: 0; 245 width: 100%; 246 } 247 248 .frontblocks .glide__slides.wp-block-group, 249 .frontblocks .glide__slides.wp-block-group.is-layout-grid { 250 display: flex; 251 grid-template-columns: none; 252 gap: 0; 253 column-gap: 0; 254 row-gap: 0; 255 } 256 257 .frontblocks .glide__slides > .glide__slide { 258 min-width: 0; 259 flex-shrink: 0; 260 } 261 262 /** 263 * GenerateBlocks (and any other plugin) may inject column-gap via generated 264 * utility classes on the carousel slides container. Glide manages its own 265 * spacing through margin-right on each slide, so any external column-gap 266 * breaks the width calculation and must be zeroed out. 267 */ 268 .frontblocks-carousel, 269 .frontblocks .glide__slides { 270 column-gap: 0 !important; 271 gap: 0 !important; 272 } -
frontblocks/trunk/assets/carousel/frontblocks-carousel.js
r3462660 r3472405 29 29 parentwrap.replaceChild(wrapperParent, wrapper); 30 30 wrapperParent.appendChild(wrapper); 31 wrapperParent.classList.add(' glide');31 wrapperParent.classList.add('frontblocks', 'glide'); 32 32 33 33 // Options … … 38 38 const carouselTabletView = item.getAttribute('data-tablet-view') ? parseInt(item.getAttribute('data-tablet-view')) : 2; 39 39 const carouselMobileView = item.getAttribute('data-mobile-view') ? parseInt(item.getAttribute('data-mobile-view')) : 1; 40 const autoplayValue = item.getAttribute('data-autoplay'); 41 const carouselAutoplay = autoplayValue && autoplayValue !== '' ? parseInt(autoplayValue) : 0; 40 const autoplayAttr = item.getAttribute('data-autoplay'); 41 const carouselAutoplay = (autoplayAttr !== '' && autoplayAttr !== null && autoplayAttr !== undefined) ? parseInt(autoplayAttr, 10) : 0; 42 const carouselGap = item.getAttribute('data-gap') ? parseInt(item.getAttribute('data-gap'), 10) : 20; 42 43 const carouselRewind = item.getAttribute('data-rewind') ? item.getAttribute('data-rewind') : false; 43 44 const carouselbuttonsColor = item.getAttribute('data-buttons-color') ? item.getAttribute('data-buttons-color') : 'black'; … … 64 65 bullets.classList.add('glide__bullets'); 65 66 bullets.setAttribute('data-glide-el', 'controls[nav]'); 67 bullets.setAttribute('role', 'group'); 68 bullets.setAttribute('aria-label', 'Slide navigation'); 66 69 67 70 for (let i = 0; i < item.children.length; i++) { … … 70 73 bullet.setAttribute('data-glide-dir', '=' + i); 71 74 bullet.setAttribute('aria-label', 'Go to slide ' + (i + 1)); 72 bullet.style.backgroundColor = carouselbuttonsBackgroundColor;73 75 bullets.appendChild(bullet); 74 76 } … … 76 78 wrapperParent.appendChild(bullets); 77 79 78 // Add custom CSS for active bullet color79 const style = document.createElement('style');80 style.textContent = `81 .glide__bullet.glide__bullet--active { 82 background-color: ${carouselbuttonsColor} !important; 83 } 84 `;85 document.head.appendChild(style);80 // Set bullet colors via CSS custom properties on the wrapper. 81 // This avoids specificity conflicts with the stylesheet. 82 if (carouselbuttonsColor) { 83 wrapperParent.style.setProperty('--frbl-bullet-color', carouselbuttonsColor); 84 } 85 if (carouselbuttonsBackgroundColor && carouselbuttonsBackgroundColor !== 'transparent') { 86 wrapperParent.style.setProperty('--frbl-bullet-bg', carouselbuttonsBackgroundColor); 87 } 86 88 } 87 89 … … 110 112 wrapperParent.appendChild(arrows); 111 113 } 112 // Calculate gap based on perView - use 0 gap when showing 1 slide113 const calculateGap = (view) => view === 1 ? 0 : 20;114 115 114 const glideFrontBlocks = new Glide(wrapperParent, { 116 115 type: carouselType, 117 116 perView: carouselView, 118 117 startAt: 0, 119 autoplay: carouselAutoplay === 0 ? false : carouselAutoplay,120 gap: calculateGap(carouselView),118 autoplay: carouselAutoplay > 0 ? carouselAutoplay : false, 119 gap: isNaN(carouselGap) ? 20 : carouselGap, 121 120 rewind: carouselRewind, 122 121 breakpoints: { 123 122 768: { 124 perView: carouselMobileView, 125 gap: calculateGap(carouselMobileView) 123 perView: carouselMobileView 126 124 }, 127 125 1024: { 128 perView: carouselTabletView, 129 gap: calculateGap(carouselTabletView) 126 perView: carouselTabletView 130 127 }, 131 128 1440: { 132 perView: carouselLaptopView, 133 gap: calculateGap(carouselLaptopView) 129 perView: carouselLaptopView 134 130 } 135 131 } -
frontblocks/trunk/assets/gravityforms-inline/frontblocks-gf-inline.css
r3402582 r3472405 174 174 } 175 175 176 /* ------------------------------------------------------------------------- 177 GenerateBlocks Accordion + Gravity Form: remove blank space when closed 178 When a Gravity Form is inside a GB accordion and the accordion is above 179 the footer, the closed content can still reserve space. Force it to none. 180 ------------------------------------------------------------------------- */ 181 .gb-accordion__item:not(.gb-accordion__item-open):not([data-accordion-is-open="true"]) > .gb-accordion__content { 182 display: none; 183 overflow: hidden; 184 max-height: 0; 185 min-height: 0 ; 186 margin: 0 ; 187 padding: 0 ; 188 visibility: hidden; 189 } 190 191 /* Prevent Gravity Form wrapper from forcing height when inside closed accordion. */ 192 .gb-accordion__item:not(.gb-accordion__item-open):not([data-accordion-is-open="true"]) > .gb-accordion__content .gform_wrapper { 193 min-height: 0; 194 height: 0; 195 overflow: hidden; 196 visibility: hidden; 197 } 198 -
frontblocks/trunk/assets/shape-animations/frontblocks-shape-animation-option.js
r3409365 r3472405 19 19 PanelBody = _wp$components.PanelBody, 20 20 ToggleControl = _wp$components.ToggleControl, 21 TextareaControl = _wp$components.TextareaControl, 21 22 Button = _wp$components.Button, 22 Notice = _wp$components.Notice, 23 FormFileUpload = _wp$components.FormFileUpload; 23 Notice = _wp$components.Notice; 24 24 25 25 /** … … 46 46 jsonPreview = _useState4[0], 47 47 setJsonPreview = _useState4[1]; 48 var _useState5 = useState(''),49 _useState6 = _slicedToArray(_useState5, 2),50 fileName = _useState6[0],51 setFileName = _useState6[1];52 var _useState7 = useState(0),53 _useState8 = _slicedToArray(_useState7, 2),54 fileInputKey = _useState8[0],55 setFileInputKey = _useState8[1];56 48 57 49 // Detect if JSON is Lottie format. … … 101 93 }; 102 94 103 // Handle file upload. 104 var handleFileUpload = function handleFileUpload(event) { 105 var file = event.target.files[0]; 106 if (!file) { 107 return; 108 } 109 110 // Check if it's a JSON file. 111 if (!file.name.endsWith('.json')) { 112 setJsonError(__('Please select a JSON file', 'frontblocks')); 113 setFileInputKey(function(prev) { return prev + 1; }); 114 return; 115 } 116 117 setFileName(file.name); 118 119 // Read file content. 120 var reader = new FileReader(); 121 reader.onload = function(e) { 122 var content = e.target.result; 123 setAttributes({ frblCustomSvgAnimationJson: content }); 124 validateJson(content); 125 setFileInputKey(function(prev) { return prev + 1; }); 126 }; 127 reader.onerror = function() { 128 setJsonError(__('Error reading file', 'frontblocks')); 129 setFileInputKey(function(prev) { return prev + 1; }); 130 }; 131 reader.readAsText(file); 95 // Handle JSON change. 96 var handleJsonChange = function handleJsonChange(value) { 97 setAttributes({ 98 frblCustomSvgAnimationJson: value 99 }); 100 if (value.trim()) { 101 validateJson(value); 102 } else { 103 setJsonError(''); 104 setJsonPreview(null); 105 } 132 106 }; 133 134 // Clear imported JSON. 135 var handleClear = function handleClear() { 136 setAttributes({ frblCustomSvgAnimationJson: '' }); 137 setJsonError(''); 138 setJsonPreview(null); 139 setFileName(''); 140 setFileInputKey(function(prev) { return prev + 1; }); 141 }; 142 107 143 108 // Example JSON template. 144 109 var exampleJson = JSON.stringify({ … … 153 118 } 154 119 }, null, 2); 155 156 // Download example JSON.157 var handleDownloadExample = function handleDownloadExample() {158 var blob = new Blob([exampleJson], { type: 'application/json' });159 var url = URL.createObjectURL(blob);160 var a = document.createElement('a');161 a.href = url;162 a.download = 'example-animation.json';163 document.body.appendChild(a);164 a.click();165 document.body.removeChild(a);166 URL.revokeObjectURL(url);167 };168 169 120 return wp.element.createElement(Fragment, {}, wp.element.createElement(BlockEdit, props), wp.element.createElement(InspectorControls, {}, wp.element.createElement(PanelBody, { 170 121 title: __('FrontBlocks Custom SVG Animation', 'frontblocks'), … … 182 133 style: { 183 134 fontSize: '12px', 184 marginBottom: ' 12px',135 marginBottom: '8px', 185 136 color: '#757575' 186 137 } 187 }, __('Import a JSON file with your animation configuration:', 'frontblocks')), wp.element.createElement(FormFileUpload, { 188 key: fileInputKey, 189 accept: '.json', 190 onChange: handleFileUpload, 191 render: function(ref) { 192 return wp.element.createElement(Button, { 193 isSecondary: true, 194 onClick: ref.openFileDialog, 195 style: { marginBottom: '8px', width: '100%' } 196 }, fileName ? __('Change JSON file', 'frontblocks') : __('Import JSON file', 'frontblocks')); 197 } 198 }), fileName && wp.element.createElement('div', { 199 style: { 200 display: 'flex', 201 alignItems: 'center', 202 justifyContent: 'space-between', 203 marginBottom: '12px', 204 padding: '8px', 205 background: '#f6f7f7', 206 borderRadius: '4px', 207 fontSize: '12px' 208 } 209 }, wp.element.createElement('span', {}, '📄 ' + fileName), wp.element.createElement(Button, { 210 isSmall: true, 211 isDestructive: true, 212 onClick: handleClear 213 }, __('Clear', 'frontblocks'))), jsonError && wp.element.createElement(Notice, { 138 }, __('Paste your JSON configuration below:', 'frontblocks')), wp.element.createElement(TextareaControl, { 139 label: __('JSON Configuration', 'frontblocks'), 140 value: frblCustomSvgAnimationJson, 141 onChange: handleJsonChange, 142 rows: 10, 143 help: __('JSON with svg and animation properties', 'frontblocks') 144 }), jsonError && wp.element.createElement(Notice, { 214 145 status: 'error', 215 146 isDismissible: false … … 228 159 marginBottom: '8px' 229 160 } 230 }, __('📋 Downloadexample JSON', 'frontblocks')), wp.element.createElement('pre', {161 }, __('📋 Show example JSON', 'frontblocks')), wp.element.createElement('pre', { 231 162 style: { 232 163 background: '#f6f7f7', … … 240 171 isSecondary: true, 241 172 isSmall: true, 242 onClick: handleDownloadExample,243 style: {244 marginTop: '8px',245 marginRight: '8px'246 }247 }, __('Download example', 'frontblocks')), wp.element.createElement(Button, {248 isSecondary: true,249 isSmall: true,250 173 onClick: function onClick() { 251 174 setAttributes({ 252 175 frblCustomSvgAnimationJson: exampleJson 253 176 }); 254 setFileName('example-animation.json');255 177 validateJson(exampleJson); 256 setFileInputKey(function(prev) { return prev + 1; });257 178 }, 258 179 style: { -
frontblocks/trunk/assets/stacked-images/frontblocks-stacked-images-frontend.js
r3462660 r3472405 78 78 entries.forEach(entry => { 79 79 if (entry.isIntersecting) { 80 container.classList.add('frbl-animated'); 80 81 animateImages(images, duration, delay); 81 82 observer.unobserve(entry.target); … … 84 85 }, 85 86 { 86 threshold: 0. 2,87 rootMargin: ' 0px',87 threshold: 0.05, 88 rootMargin: '50px 0px 50px 0px', 88 89 } 89 90 ); 90 91 91 92 observer.observe(container); 93 94 // Fallback: if observer never fires (e.g. layout/height issue on mobile), animate after a short delay. 95 setTimeout(() => { 96 if (!container.classList.contains('frbl-animated')) { 97 container.classList.add('frbl-animated'); 98 animateImages(images, duration, delay); 99 } 100 }, 800); 92 101 }); 93 102 } -
frontblocks/trunk/assets/stacked-images/frontblocks-stacked-images.css
r3462660 r3472405 3 3 */ 4 4 5 /* Wrapper */5 /* Wrapper – centered, compact size on all viewports */ 6 6 .frbl-stacked-images-wrapper { 7 7 position: relative; 8 8 width: 100%; 9 max-width: 520px; 10 max-height: 65vh; 11 margin-left: auto; 12 margin-right: auto; 9 13 overflow: visible; 10 14 display: block; 11 15 background: transparent; 12 padding: 50px;13 margin: -50px;16 padding: 40px; 17 box-sizing: border-box; 14 18 } 15 19 16 /* Container */20 /* Container – center content horizontally and vertically */ 17 21 .frbl-stacked-images-container { 18 22 position: relative; … … 23 27 justify-content: center; 24 28 overflow: visible; 29 margin: 0 auto; 25 30 } 26 31 27 /* Individual image */32 /* Individual image – flex center so img is always centered */ 28 33 .frbl-stacked-image { 29 34 position: absolute; 30 35 top: 0; 31 36 left: 0; 37 right: 0; 38 bottom: 0; 32 39 width: 100%; 33 40 height: 100%; … … 39 46 visibility: hidden; 40 47 overflow: visible; 48 margin: auto; 41 49 } 42 50 … … 47 55 48 56 .frbl-stacked-image img { 49 max-width: 100%;50 max-height: 100%;57 max-width: 85%; 58 max-height: 85%; 51 59 width: auto; 52 60 height: auto; 53 61 object-fit: contain; 62 object-position: center; 54 63 display: block; 64 margin: auto; 55 65 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 56 66 } … … 99 109 } 100 110 101 /* Responsive */ 111 /* Tablet / ventana media: aquí suele verse enorme, lo limitamos mucho */ 112 @media (min-width: 769px) and (max-width: 1200px) { 113 .frbl-stacked-images-wrapper { 114 max-width: 420px; 115 max-height: 55vh; 116 padding: 24px; 117 } 118 .frbl-stacked-image img { 119 max-width: 82%; 120 max-height: 82%; 121 } 122 } 123 124 /* Mobile */ 102 125 @media (max-width: 768px) { 103 126 .frbl-stacked-images-wrapper { 104 height: auto !important; 105 min-height: 300px; 127 min-height: 260px; 128 max-height: 60vh; 129 max-width: 88%; 130 margin-left: auto; 131 margin-right: auto; 132 padding: 20px; 133 } 134 .frbl-stacked-images-container { 135 min-height: 260px; 136 margin: 0 auto; 137 } 138 .frbl-stacked-image img { 139 max-width: 85%; 140 max-height: 55vh; 141 object-position: center; 142 margin: auto; 106 143 } 107 144 } -
frontblocks/trunk/frontblocks.php
r3462660 r3472405 1 1 <?php 2 2 /** 3 * Plugin Name: FrontBlocks for G eneratePress3 * Plugin Name: FrontBlocks for Gutenberg/GeneratePress 4 4 * Plugin URI: https://wordpress.org/plugins/frontblocks/ 5 * Description: Blocks and helpers that extends G eneratePress blocks.6 * Version: 1.3. 25 * Description: Blocks and helpers that extends Gutenberg and GeneratePress blocks. 6 * Version: 1.3.3 7 7 * Author: Closemarketing 8 8 * Author URI: https://close.marketing … … 27 27 defined( 'ABSPATH' ) || die( 'No script kiddies please!' ); 28 28 29 define( 'FRBL_VERSION', '1.3. 2' );29 define( 'FRBL_VERSION', '1.3.3' ); 30 30 define( 'FRBL_PLUGIN', __FILE__ ); 31 31 define( 'FRBL_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); -
frontblocks/trunk/includes/Frontend/Carousel.php
r3409365 r3472405 34 34 private function init_hooks() { 35 35 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) ); 36 add_action( 'enqueue_block_assets', array( $this, 'enqueue_block_canvas_assets' ) ); 36 37 add_filter( 'render_block_generateblocks/grid', array( $this, 'add_custom_attributes_to_grid_block' ), 10, 2 ); 37 38 add_filter( 'render_block_generateblocks/element', array( $this, 'add_custom_attributes_to_element_block' ), 10, 2 ); 38 39 add_filter( 'render_block_core/group', array( $this, 'add_custom_attributes_to_core_group_block' ), 10, 2 ); 39 40 add_action( 'init', array( $this, 'register_custom_attributes' ), 5 ); 41 } 42 43 /** 44 * Enqueue carousel CSS in the editor canvas (iframe). 45 * 46 * @return void 47 */ 48 public function enqueue_block_canvas_assets() { 49 if ( ! is_admin() ) { 50 return; 51 } 52 wp_enqueue_style( 53 'frontblocks-carousel-editor', 54 FRBL_PLUGIN_URL . 'assets/carousel/frontblocks-carousel-editor.css', 55 array(), 56 FRBL_VERSION 57 ); 40 58 } 41 59 … … 76 94 $responsive_to_view = isset( $attrs['frblResponsiveToView'] ) ? (int) $attrs['frblResponsiveToView'] : 1; 77 95 $autoplay = isset( $attrs['frblAutoplay'] ) ? ( (int) $attrs['frblAutoplay'] * 1000 ) : ''; 96 $gap = isset( $attrs['frblGap'] ) && '' !== $attrs['frblGap'] ? (int) $attrs['frblGap'] : 20; 78 97 $rewind = isset( $attrs['frblRewind'] ) ? (bool) $attrs['frblRewind'] : true; 79 98 $buttons = isset( $attrs['frblButtons'] ) ? sanitize_text_field( $attrs['frblButtons'] ) : 'arrows'; … … 100 119 ' data-mobile-view="' . esc_attr( $responsive_to_view ) . '"' . 101 120 ' data-autoplay="' . esc_attr( $autoplay ) . '"' . 121 ' data-gap="' . esc_attr( $gap ) . '"' . 102 122 ' data-buttons="' . esc_attr( $buttons ) . '"' . 103 123 ' data-buttons-color="' . esc_attr( $button_color ) . '"' . … … 140 160 $responsive_to_view = isset( $attrs['frblResponsiveToView'] ) ? (int) $attrs['frblResponsiveToView'] : 1; 141 161 $autoplay = isset( $attrs['frblAutoplay'] ) ? ( (int) $attrs['frblAutoplay'] * 1000 ) : ''; 162 $gap = isset( $attrs['frblGap'] ) && '' !== $attrs['frblGap'] ? (int) $attrs['frblGap'] : 20; 142 163 $rewind = isset( $attrs['frblRewind'] ) ? (bool) $attrs['frblRewind'] : true; 143 164 $buttons = isset( $attrs['frblButtons'] ) ? sanitize_text_field( $attrs['frblButtons'] ) : 'arrows'; … … 164 185 ' data-mobile-view="' . esc_attr( $responsive_to_view ) . '"' . 165 186 ' data-autoplay="' . esc_attr( $autoplay ) . '"' . 187 ' data-gap="' . esc_attr( $gap ) . '"' . 166 188 ' data-buttons="' . esc_attr( $buttons ) . '"' . 167 189 ' data-buttons-color="' . esc_attr( $button_color ) . '"' . … … 204 226 $responsive_to_view = isset( $attrs['frblResponsiveToView'] ) ? (int) $attrs['frblResponsiveToView'] : 1; 205 227 $autoplay = isset( $attrs['frblAutoplay'] ) ? ( (int) $attrs['frblAutoplay'] * 1000 ) : ''; 228 $gap = isset( $attrs['frblGap'] ) && '' !== $attrs['frblGap'] ? (int) $attrs['frblGap'] : 20; 206 229 $rewind = isset( $attrs['frblRewind'] ) ? (bool) $attrs['frblRewind'] : true; 207 230 $buttons = isset( $attrs['frblButtons'] ) ? sanitize_text_field( $attrs['frblButtons'] ) : 'arrows'; … … 228 251 ' data-mobile-view="' . esc_attr( $responsive_to_view ) . '"' . 229 252 ' data-autoplay="' . esc_attr( $autoplay ) . '"' . 253 ' data-gap="' . esc_attr( $gap ) . '"' . 230 254 ' data-buttons="' . esc_attr( $buttons ) . '"' . 231 255 ' data-buttons-color="' . esc_attr( $button_color ) . '"' . … … 299 323 'type' => 'string', 300 324 'default' => '', 325 ); 326 $block_args['attributes']['frblGap'] = array( 327 'type' => 'string', 328 'default' => '20', 301 329 ); 302 330 $block_args['attributes']['frblRewind'] = array( … … 371 399 default: '' 372 400 }, 401 frblGap: { 402 type: 'string', 403 default: '20' 404 }, 373 405 frblButtons: { 374 406 type: 'string', -
frontblocks/trunk/readme.txt
r3462660 r3472405 1 === FrontBlocks for Gutenberg andGeneratePress ===1 === FrontBlocks for Gutenberg/GeneratePress === 2 2 Contributors: davidperez, sacrajaimez, alexbreagarcia, matiasquero, amulero, mit2sumit, alexcm13 3 3 Tags: carrusel, slider, lightweight, generatepress, gutenberg 4 4 Donate link: https://close.marketing/go/donate/ 5 5 Requires at least: 5.0 6 Tested up to: 6.97 Stable tag: 1.3. 28 Version: 1.3. 26 Tested up to: 7.0 7 Stable tag: 1.3.3 8 Version: 1.3.3 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html 11 11 12 This plugin extends the functionality of GeneratePress by adding a carousel, slider, animations, sticky columns, edge alignment for containers and the ability to insert posts.12 Plugin extending Gutenberg and GeneratePress with carousel, slider, animations, sticky columns, edge alignment and post insertion capabilities. 13 13 14 14 == Description == … … 153 153 154 154 == Changelog == 155 156 == 1.3.3 == 157 * Fixed: Carousel bullets display and behavior. 158 * Fixed: Carousel editor styling and functionality. 159 * Fixed: Carousel in native (core) blocks. 160 * Fixed: Carousel JavaScript and CSS issues. 161 * Fixed: Stacked images block display. 162 * Fixed: Accordion in Gravity Forms inline layout. 163 * Improved: Carousel styles - updated classes and removed unnecessary declarations. 164 * Improved: Settings page and carousel advanced options. 165 * Improved: Shape animations option component. 166 * Improved: PHPStan compliance and code quality. 155 167 156 168 == 1.3.2 == -
frontblocks/trunk/vendor/composer/installed.php
r3462660 r3472405 2 2 'root' => array( 3 3 'name' => 'close/frontblocks', 4 'pretty_version' => '1.3. 2',5 'version' => '1.3. 2.0',6 'reference' => ' 95247c40e9617d1fb79fb93f1daf791fb7e918db',4 'pretty_version' => '1.3.3', 5 'version' => '1.3.3.0', 6 'reference' => '7fb5a8fa3abcff0754a417193682455d7af5dc2d', 7 7 'type' => 'library', 8 8 'install_path' => __DIR__ . '/../../', … … 12 12 'versions' => array( 13 13 'close/frontblocks' => array( 14 'pretty_version' => '1.3. 2',15 'version' => '1.3. 2.0',16 'reference' => ' 95247c40e9617d1fb79fb93f1daf791fb7e918db',14 'pretty_version' => '1.3.3', 15 'version' => '1.3.3.0', 16 'reference' => '7fb5a8fa3abcff0754a417193682455d7af5dc2d', 17 17 'type' => 'library', 18 18 'install_path' => __DIR__ . '/../../',
Note: See TracChangeset
for help on using the changeset viewer.