1(function (window, document) { 2 'use strict'; 3 4 var ROOT_ID = 'ssupl-featured-gear-brands'; 5 var STYLE_ID = 'ssupl-featured-gear-brands-style'; 6 var MOBILE_BREAKPOINT = 767; 7 8 /* ========================================================= 9 FEATURED GEAR BRANDS 10 image í목ì ì¬ì©í ë©ì¸ ì´ë¯¸ì§ URLë§ ì ë ¥íë©´ ë©ëë¤. 11 ========================================================= */ 12 13 var BRANDS = [ 14 { 15 name: 'SHOEI', 16 href: '/goods/goods_list.php?cateCd=008414', 17 image: 'https://ssupl01.hgodo.com/img_new/goods/editor/250521/b87e060654ece51e54a57a71b9390d23_155038.png', 18 imageAlt: 'SHOEI ì¼ìì´', 19 logo: '/data/skin/front/19-07_C/img/etc/e/a_11.jpg', 20 logoAlt: 'SHOEI', 21 description: 'ë¼ì´ë©ì ìí í리미ì í¬ë©§' 22 }, 23 { 24 name: 'HJC', 25 href: '/goods/goods_list.php?cateCd=008287', 26 image: 'https://ssupl01.hgodo.com/img_new/goods/editor/240809/1d26396396e8958812530f60cda8086a_143732.jpg', 27 imageAlt: 'HJC í¬ë©§', 28 logo: 'https://ssupl01.hgodo.com/img/etc/main/hjc.jpg', 29 logoAlt: 'HJC', 30 description: 'ì¸ê³ê° ì íí í리미ì 모í°ì¬ì´í´ í¬ë©§' 31 }, 32 { 33 name: 'ALPINESTARS', 34 href: '/goods/goods_list.php?cateCd=008256', 35 image: 'https://ssupl01.hgodo.com/img_new/goods/editor/260517/a558b7189ef92fbc4b442ee843ad48f7_021103.jpg', 36 imageAlt: 'ìíì¸ì¤íì¦ ALPINESTARS', 37 logo: '/data/skin/front/19-07_C/img/etc/e/a_14.jpg', 38 logoAlt: 'ALPINESTARS', 39 description: 'ë ì´ì±ìì ììë í리미ì ë¼ì´ë© 기ì´' 40 }, 41 { 42 name: "REV'IT", 43 href: '/goods/goods_list.php?cateCd=008321', 44 image: "https://www.bikepop.co.kr/bemarket/revit3/quantum3h2ojacket_top5.jpg", 45 imageAlt: "ë ë¹ REV'IT", 46 logo: '/data/skin/front/19-07_C/img/etc/e/a_16.jpg', 47 logoAlt: "REV'IT", 48 description: '기ë¥ê³¼ ì¤íì¼ì ê²°í©í í리미ì ë¼ì´ë© 기ì´' 49 }, 50 { 51 name: 'DAYTONA', 52 href: '/goods/goods_list.php?cateCd=008477', 53 image: 'https://godomall-storage.cdn-nhncommerce.com/44751f1b0dd5a7a4197137ced7bf7245/editor/goods/category-goods/36/b89ec8483f40fd84a7b68b645ba50849.png', 54 imageAlt: 'DAYTONA ë°ì´í ë', 55 logo: 'https://ssupl01.hgodo.com/img/etc/main/daytona.jpg', 56 logoAlt: 'DAYTONA', 57 description: '매ì¼ì ë¼ì´ë©ì ë í¸ë¦¬íê² ë§ëë 모í°ì¬ì´í´ 기ì´' 58 } 59 ]; 60 61 62 /* ========================================================= 63 UTIL 64 ========================================================= */ 65 66 function pad(number) { 67 return number < 10 ? '0' + number : String(number); 68 } 69 70 function escapeHtml(value) { 71 return String(value) 72 .replace(/&/g, '&') 73 .replace(/</g, '<') 74 .replace(/>/g, '>') 75 .replace(/"/g, '"') 76 .replace(/'/g, '''); 77 } 78 79 function shuffleBrands(items) { 80 var shuffled = items.slice(); 81 82 for (var i = shuffled.length - 1; i > 0; i--) { 83 var randomIndex = Math.floor(Math.random() * (i + 1)); 84 var temporary = shuffled[i]; 85 86 shuffled[i] = shuffled[randomIndex]; 87 shuffled[randomIndex] = temporary; 88 } 89 90 return shuffled; 91 } 92 93 94 /* ========================================================= 95 STYLE 96 ========================================================= */ 97 98 function addStyle() { 99 if (document.getElementById(STYLE_ID)) { 100 return; 101 } 102 103 var style = document.createElement('style'); 104 style.id = STYLE_ID; 105 106 style.textContent = [ 107 108 '#' + ROOT_ID + ',', 109 '#' + ROOT_ID + ' *{', 110 'box-sizing:border-box;', 111 '}', 112 113 '#' + ROOT_ID + '{', 114 'position:relative;', 115 'width:100%;', 116 'margin:0;', 117 'padding:28px 0 0;', 118 'overflow:hidden;', 119 'background:#fff;', 120 'color:#111;', 121 'font-family:-apple-system,BlinkMacSystemFont,"Pretendard","Noto Sans KR","Apple SD Gothic Neo",Arial,sans-serif;', 122 '}', 123 124 '#' + ROOT_ID + ' a{', 125 'color:inherit;', 126 'text-decoration:none;', 127 '}', 128 129 '#' + ROOT_ID + ' button{', 130 'font-family:inherit;', 131 '}', 132 133 134 /* ============================== 135 INNER 136 ============================== */ 137 138 '#' + ROOT_ID + ' .sfg-inner{', 139 'position:relative;', 140 'width:100%;', 141 'max-width:1200px;', 142 'margin:0 auto;', 143 'padding:0;', 144 '}', 145 146 147 /* ============================== 148 COUNT 149 ============================== */ 150 151 '#' + ROOT_ID + ' .sfg-top{', 152 'display:flex;', 153 'align-items:center;', 154 'justify-content:flex-end;', 155 'min-height:18px;', 156 'margin-bottom:14px;', 157 '}', 158 159 '#' + ROOT_ID + ' .sfg-count{', 160 'color:#aaa;', 161 'font-size:12px;', 162 'line-height:1;', 163 '}', 164 165 '#' + ROOT_ID + ' .sfg-current{', 166 'color:#111;', 167 'font-weight:800;', 168 '}', 169 170 171 /* ============================== 172 SLIDER 173 ============================== */ 174 175 '#' + ROOT_ID + ' .sfg-stage{', 176 'position:relative;', 177 '}', 178 179 '#' + ROOT_ID + ' .sfg-viewport{', 180 'width:100%;', 181 'overflow:hidden;', 182 'touch-action:pan-y;', 183 '}', 184 185 '#' + ROOT_ID + ' .sfg-track{', 186 'display:flex;', 187 'align-items:stretch;', 188 'margin:0;', 189 'padding:0;',
190 'transform:translate3d(0,0,0);', 191 'transition:transform .45s cubic-bezier(.22,.61,.36,1);', 192 'will-change:transform;', 193 '}', 194 195 196 /* ============================== 197 CARD 198 ============================== */ 199 200 '#' + ROOT_ID + ' .sfg-card{', 201 'display:block;', 202 'position:relative;', 203 'flex:0 0 auto;', 204 'min-width:0;', 205 'aspect-ratio:4/3;', 206 'overflow:hidden;', 207 'border:0;', 208 'background:#111;', 209 'isolation:isolate;', 210 '}', 211 212 '#' + ROOT_ID + ' .sfg-image{', 213 'position:absolute;', 214 'inset:0;', 215 'z-index:-3;', 216 'width:100%;', 217 'height:100%;', 218 'overflow:hidden;', 219 'background:#111;', 220 '}', 221 222 '#' + ROOT_ID + ' .sfg-image img{', 223 'display:block;', 224 'width:100%;', 225 'height:100%;', 226 'object-fit:cover;', 227 'transition:transform .45s ease;', 228 '}', 229 230 '#' + ROOT_ID + ' .sfg-card:hover .sfg-image img{', 231 'transform:scale(1.035);', 232 '}', 233 234 '#' + ROOT_ID + ' .sfg-card:before{', 235 'content:"";', 236 'position:absolute;', 237 'inset:0;', 238 'z-index:-2;', 239 'background:linear-gradient(180deg,rgba(0,0,0,0) 30%,rgba(0,0,0,.12) 48%,rgba(0,0,0,.88) 100%);', 240 '}', 241 242 '#' + ROOT_ID + ' .sfg-card:after{', 243 'content:"";', 244 'position:absolute;', 245 'inset:0;', 246 'z-index:-1;', 247 'background:linear-gradient(90deg,rgba(0,0,0,.25),rgba(0,0,0,0) 65%);', 248 '}', 249 250 251 /* ============================== 252 COPY 253 ============================== */ 254 255 '#' + ROOT_ID + ' .sfg-copy{', 256 'position:absolute;', 257 'right:0;', 258 'bottom:0;', 259 'left:0;', 260 'z-index:2;', 261 'width:100%;', 262 'padding:24px;', 263 'color:#fff;', 264 '}', 265 266 '#' + ROOT_ID + ' .sfg-logo{', 267 'display:inline-flex;', 268 'align-items:center;', 269 'width:auto;', 270 'height:30px;', 271 'margin:0 0 13px;', 272 'padding:5px 9px;', 273 'background:#fff;', 274 '}', 275 276 '#' + ROOT_ID + ' .sfg-logo img{', 277 'display:block;', 278 'width:auto;', 279 'max-width:110px;', 280 'height:auto;', 281 'max-height:20px;', 282 'object-fit:contain;', 283 '}', 284 285 '#' + ROOT_ID + ' .sfg-copy h3{', 286 'margin:0;', 287 'color:#fff;', 288 'font-size:18px;', 289 'font-weight:750;', 290 'line-height:1.4;', 291 'letter-spacing:-.45px;', 292 'word-break:keep-all;', 293 'text-shadow:0 2px 8px rgba(0,0,0,.4);', 294 '}', 295 296 '#' + ROOT_ID + ' .sfg-brand-link{', 297 'display:flex;', 298 'align-items:center;', 299 'justify-content:space-between;', 300 'margin-top:14px;', 301 'color:rgba(255,255,255,.78);', 302 'font-size:12px;', 303 'font-weight:600;', 304 'line-height:1;', 305 '}', 306 307 '#' + ROOT_ID + ' .sfg-brand-link b{', 308 'margin-left:auto;', 309 'color:#fff;', 310 'font-size:16px;', 311 'font-weight:400;', 312 '}', 313 314 315 /* ============================== 316 ARROWS 317 ============================== */ 318 319 '#' + ROOT_ID + ' .sfg-arrow{', 320 'display:flex;', 321 'align-items:center;', 322 'justify-content:center;', 323 'position:absolute;', 324 'top:50%;', 325 'z-index:5;', 326 'width:42px;', 327 'height:42px;', 328 'margin:0;', 329 'padding:0;', 330 'border:1px solid #ddd;', 331 'border-radius:50%;', 332 'background:rgba(255,255,255,.96);', 333 'color:#222;', 334 'font-size:24px;', 335 'line-height:1;', 336 'box-shadow:0 4px 14px rgba(0,0,0,.14);', 337 'transform:translateY(-50%);', 338 'cursor:pointer;', 339 '}', 340 341 '#' + ROOT_ID + ' .sfg-prev{', 342 'left:10px;', 343 '}', 344 345 '#' + ROOT_ID + ' .sfg-next{', 346 'right:10px;', 347 '}', 348 349 '#' + ROOT_ID + ' .sfg-arrow:disabled{', 350 'opacity:.3;',
351 'cursor:default;', 352 '}', 353 354 355 /* ============================== 356 PROGRESS 357 ============================== */ 358 359 '#' + ROOT_ID + ' .sfg-progress{', 360 'position:relative;', 361 'width:100%;', 362 'height:2px;', 363 'margin-top:26px;', 364 'overflow:hidden;', 365 'background:#e8e8e8;', 366 '}', 367 368 '#' + ROOT_ID + ' .sfg-progress-bar{', 369 'display:block;', 370 'width:0;', 371 'height:100%;', 372 'background:#111;', 373 'transition:width .35s ease;', 374 '}', 375 376 377 /* ============================== 378 MOBILE 379 ============================== */ 380 381 '@media screen and (max-width:767px){', 382 383 '#' + ROOT_ID + '{', 384 'padding:20px 0 0;', 385 '}', 386 387 '#' + ROOT_ID + ' .sfg-inner{', 388 'padding:0 16px;', 389 '}', 390 391 '#' + ROOT_ID + ' .sfg-top{', 392 'margin-bottom:10px;', 393 '}', 394 395 '#' + ROOT_ID + ' .sfg-count{', 396 'font-size:11px;', 397 '}', 398 399 '#' + ROOT_ID + ' .sfg-copy{', 400 'padding:20px 18px;', 401 '}', 402 403 '#' + ROOT_ID + ' .sfg-logo{', 404 'height:28px;', 405 'margin-bottom:11px;', 406 'padding:4px 8px;', 407 '}', 408 409 '#' + ROOT_ID + ' .sfg-logo img{', 410 'max-width:100px;', 411 'max-height:18px;', 412 '}', 413 414 '#' + ROOT_ID + ' .sfg-copy h3{', 415 'font-size:17px;', 416 '}', 417 418 '#' + ROOT_ID + ' .sfg-brand-link{', 419 'margin-top:12px;', 420 'font-size:11px;', 421 '}', 422 423 '#' + ROOT_ID + ' .sfg-arrow{', 424 'display:none;', 425 '}', 426 427 '#' + ROOT_ID + ' .sfg-progress{', 428 'margin-top:20px;', 429 '}', 430 431 '}', 432 433 434 /* ============================== 435 SMALL MOBILE 436 ============================== */ 437 438 '@media screen and (max-width:359px){', 439 440 '#' + ROOT_ID + ' .sfg-inner{', 441 'padding:0 12px;', 442 '}', 443 444 '#' + ROOT_ID + ' .sfg-copy{', 445 'padding:17px 15px;', 446 '}', 447 448 '#' + ROOT_ID + ' .sfg-copy h3{', 449 'font-size:16px;', 450 '}', 451 452 '}' 453 454 ].join(''); 455 456 document.head.appendChild(style); 457 } 458 459 460 /* ========================================================= 461 CREATE CARD 462 ========================================================= */ 463 464 function createCard(brand) { 465 466 return [ 467 468 '<a href="', 469 escapeHtml(brand.href), 470 '" class="sfg-card">', 471 472 '<div class="sfg-image">', 473 474 '<img src="', 475 escapeHtml(brand.image), 476 '" alt="', 477 escapeHtml(brand.imageAlt), 478 '" loading="lazy" draggable="false">', 479 480 '</div>', 481 482 '<div class="sfg-copy">', 483 484 '<div class="sfg-logo">', 485 486 '<img src="', 487 escapeHtml(brand.logo), 488 '" alt="', 489 escapeHtml(brand.logoAlt), 490 '" loading="lazy" draggable="false">', 491 492 '</div>', 493 494 '<h3>', 495 escapeHtml(brand.description), 496 '</h3>', 497 498 '<span class="sfg-brand-link">', 499 500 escapeHtml(brand.name), 501 502 '<b>â</b>', 503 504 '</span>', 505 506 '</div>', 507 508 '</a>' 509 510 ].join(''); 511 } 512 513 514 /* ========================================================= 515 RENDER 516 ========================================================= */ 517 518 function renderMainSlider(root) { 519 520 var randomizedBrands = shuffleBrands(BRANDS); 521 522 var cards = randomizedBrands 523 .map(createCard) 524 .join(''); 525 526 root.innerHTML = [ 527 528 '<div class="sfg-inner">', 529 530 '<div class="sfg-top">', 531 532 '<span class="sfg-count">', 533 534 '<b class="sfg-current">01</b>', 535 536 ' / ', 537 538 '<span class="sfg-total">01</span>', 539 540 '</span>', 541 542 '</div>', 543 544 '<div class="sfg-stage">', 545 546 '<button type="button" class="sfg-arrow sfg-prev" aria-label="ì´ì ë¸ëë">', 547 'â¹', 548 '</button>', 549 550 '<div class="sfg-viewport">', 551 552 '<div class="sfg-track">', 553 cards, 554 '</div>', 555 556 '</div>', 557 558 '<button type="button" class="sfg-arrow sfg-next" aria-label="ë¤ì ë¸ëë">', 559 'âº', 560 '</button>', 561 562 '</div>', 563 564 '<div class="sfg-progress" aria-hidden="true">', 565 566 '<span class="sfg-progress-bar"></span>', 567 568 '</div>', 569 570 '</div>' 571 572 ].join(''); 573 } 574 575 576 /* ========================================================= 577 SLIDER 578 ========================================================= */ 579 580 function startSlider(root) { 581 582 var viewport = 583 root.querySelector('.sfg-viewport'); 584 585 var track = 586 root.querySelector('.sfg-track'); 587 588 var cards = 589 Array.prototype.slice.call( 590 root.querySelectorAll('.sfg-card') 591 ); 592 593 var prevButton = 594 root.querySelector('.sfg-prev'); 595 596 var nextButton = 597 root.querySelector('.sfg-next'); 598 599 var currentText = 600 root.querySelector('.sfg-current'); 601 602 var totalText = 603 root.querySelector('.sfg-total'); 604 605 var progressBar = 606 root.querySelector('.sfg-progress-bar'); 607 608 var currentPage = 0; 609 var perView = 1; 610 var pageCount = 1; 611 var cardWidth = 0; 612 var gap = 14; 613 var resizeTimer = null; 614 var touchStartX = 0; 615 var touchMoveX = 0; 616 617 618 function update(animated) { 619 620 var offset = 621 currentPage * 622 perView * 623 (cardWidth + gap); 624 625 track.style.transition = 626 animated === false 627 ? 'none' 628 : 'transform .45s cubic-bezier(.22,.61,.36,1)'; 629 630 track.style.transform = 631 'translate3d(' + (-offset) + 'px,0,0)'; 632 633 currentText.textContent = 634 pad(currentPage + 1); 635 636 totalText.textContent = 637 pad(pageCount); 638 639 progressBar.style.width = 640 ( 641 ((currentPage + 1) / pageCount) * 642 100 643 ) + '%'; 644 645 prevButton.disabled = 646 currentPage === 0; 647 648 nextButton.disabled = 649 currentPage === pageCount - 1; 650 } 651 652 653 function setup() { 654 655 perView = 656 window.innerWidth <= MOBILE_BREAKPOINT 657 ? 1 658 : 2; 659 660 gap = 661 window.innerWidth <= MOBILE_BREAKPOINT 662 ? 10 663 : 14; 664 665 cardWidth = 666 ( 667 viewport.clientWidth - 668 (gap * (perView - 1)) 669 ) / perView; 670 671 pageCount = 672 Math.max( 673 1, 674 Math.ceil(cards.length / perView) 675 ); 676 677 currentPage = 678 Math.min( 679 currentPage, 680 pageCount - 1 681 ); 682 683 track.style.gap = 684 gap + 'px'; 685 686 cards.forEach(function (card) { 687 688 card.style.width = 689 cardWidth + 'px'; 690 691 card.style.flexBasis = 692 cardWidth + 'px'; 693 694 }); 695 696 update(false); 697 } 698 699 700 function goTo(page) { 701 702 currentPage = 703 Math.max( 704 0, 705 Math.min(page, pageCount - 1) 706 ); 707 708 update(true); 709 } 710 711 712 prevButton.onclick = function () { 713 goTo(currentPage - 1); 714 }; 715 716 717 nextButton.onclick = function () { 718 goTo(currentPage + 1); 719 }; 720 721 722 /* ============================== 723 TOUCH SWIPE 724 ============================== */ 725 726 viewport.addEventListener( 727 'touchstart', 728 function (event) { 729 730 touchStartX = 731 event.touches[0].clientX; 732 733 touchMoveX = 734 touchStartX; 735 736 }, 737 { 738 passive: true 739 } 740 ); 741 742 743 viewport.addEventListener( 744 'touchmove', 745 function (event) { 746 747 touchMoveX = 748 event.touches[0].clientX; 749 750 }, 751 { 752 passive: true 753 } 754 ); 755 756 757 viewport.addEventListener( 758 'touchend', 759 function () { 760 761 var distance = 762 touchMoveX - touchStartX; 763 764 if (distance < -40) { 765 goTo(currentPage + 1); 766 } 767 768 if (distance > 40) { 769 goTo(currentPage - 1); 770 } 771 772 } 773 ); 774 775 776 /* ============================== 777 RESIZE 778 ============================== */ 779 780 window.addEventListener( 781 'resize',
782 function () { 783 784 window.clearTimeout(resizeTimer); 785 786 resizeTimer = 787 window.setTimeout( 788 setup, 789 150 790 ); 791 792 } 793 ); 794 795 796 setup(); 797 } 798 799 800 /* ========================================================= 801 INIT 802 ========================================================= */ 803 804 function init() { 805 806 var root = 807 document.getElementById(ROOT_ID); 808 809 if (!root) { 810 return; 811 } 812 813 addStyle(); 814 815 if ( 816 root.getAttribute('data-ready') === 'true' 817 ) { 818 return; 819 } 820 821 root.setAttribute( 822 'data-ready', 823 'true' 824 ); 825 826 renderMainSlider(root); 827 startSlider(root); 828 } 829 830 831 if (document.readyState === 'loading') { 832 833 document.addEventListener( 834 'DOMContentLoaded', 835 init 836 ); 837 838 } else { 839 840 init(); 841 842 } 843 844})(window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.