1/** 2 * SurfTank Redesign â Visual Effects & Interactions 3 * Auto-loaded by framework (scans wc_js/) 4 */ 5(function () { 6 'use strict'; 7 8 // Wait for DOM 9 document.addEventListener('DOMContentLoaded', init); 10 11 function init() { 12 smoothScroll(); 13 scrollReveal(); 14 tiltCards(); 15 buttonEffects(); 16 parallaxHero(); 17 glowOnHover(); 18 animateCounters(); 19 navbarShrink(); 20 podiumLoader(); 21 } 22 23 /* ===== 1. SMOOTH SCROLL ===== */ 24 function smoothScroll() { 25 document.documentElement.style.scrollBehavior = 'smooth'; 26 // Anchor links smooth scroll with offset for sticky header 27 document.querySelectorAll('a[href^="#"]').forEach(function (a) { 28 a.addEventListener('click', function (e) { 29 var target = document.querySelector(this.getAttribute('href')); 30 if (target) { 31 e.preventDefault(); 32 var offset = 80; // header height 33 var top = target.getBoundingClientRect().top + window.pageYOffset - offset; 34 window.scrollTo({ top: top, behavior: 'smooth' }); 35 } 36 }); 37 }); 38 } 39 40 /* ===== 2. SCROLL REVEAL (fade-in on scroll) ===== */ 41 function scrollReveal() { 42 // Only animate small, repeatable elements â NOT large content containers 43 var reveals = document.querySelectorAll( 44 '.st-feature-card, .st-download-btn, ' + 45 '.st-section-title, .st-section-sub' 46 ); 47 48 if (!reveals.length) return; 49 50 reveals.forEach(function (el) { 51 el.style.opacity = '0'; 52 el.style.transform = 'translateY(24px)'; 53 el.style.transition = 'opacity 0.5s ease, transform 0.5s ease'; 54 }); 55 56 var observer = new IntersectionObserver(function (entries) { 57 entries.forEach(function (entry) { 58 if (entry.isIntersecting) { 59 var delay = entry.target.dataset.delay || 0; 60 setTimeout(function () { 61 entry.target.style.opacity = '1'; 62 entry.target.style.transform = 'translateY(0)'; 63 }, delay); 64 observer.unobserve(entry.target); 65 } 66 }); 67 }, { threshold: 0.05, rootMargin: '0px 0px -30px 0px' }); 68 69 // Stagger delays for sibling groups 70 var groups = {}; 71 reveals.forEach(function (el) { 72 var parent = el.parentElement; 73 var key = parent ? (parent.className || 'root') : 'root'; 74 if (!groups[key]) groups[key] = []; 75 groups[key].push(el); 76 }); 77 Object.values(groups).forEach(function (group) { 78 group.forEach(function (el, i) { 79 el.dataset.delay = i * 120; 80 }); 81 }); 82 83 reveals.forEach(function (el) { observer.observe(el); }); 84 } 85 86 /* ===== 3. TILT 3D EFFECT ON CARDS ===== */ 87 function tiltCards() { 88 var cards = document.querySelectorAll('.server-card-inner, .st-feature-card, .st-download-btn'); 89 cards.forEach(function (card) { 90 card.addEventListener('mousemove', function (e) { 91 var rect = card.getBoundingClientRect(); 92 var x = e.clientX - rect.left; 93 var y = e.clientY - rect.top; 94 var centerX = rect.width / 2; 95 var centerY = rect.height / 2; 96 var rotateX = ((y - centerY) / centerY) * -6; 97 var rotateY = ((x - centerX) / centerX) * 6; 98 card.style.transform = 'perspective(600px) rotateX(' + rotateX + 'deg) rotateY(' + rotateY + 'deg) scale(1.02)'; 99 }); 100 card.addEventListener('mouseleave', function () { 101 card.style.transform = 'perspective(600px) rotateX(0) rotateY(0) scale(1)'; 102 }); 103 }); 104 } 105 106 /* ===== 4. BUTTON SHINE EFFECT ===== */ 107 function buttonEffects() { 108 var btns = document.querySelectorAll( 109 '.btn-st-blue, .btn-st-orange, .btn-st-green, .btn-st-purple, ' + 110 '.btn-header-login, .btn-header-register, .btn-header-play, ' + 111 '.st-quick-action, .btn_green, .btn_blue' 112 ); 113 btns.forEach(function (btn) { 114 btn.style.position = 'relative'; 115 btn.style.overflow = 'hidden'; 116 btn.addEventListener('mouseenter', function (e) { 117 var shine = document.createElement('span'); 118 shine.className = 'btn-shine'; 119 shine.style.cssText = 120 'position:absolute;top:0;left:-100%;width:100%;height:100%;' + 121 'background:linear-gradient(90deg,transparent,rgba(255,255,255,0.2),transparent);' + 122 'animation:btnShine 0.6s ease-out forwards;pointer-events:none;'; 123 btn.appendChild(shine); 124 setTimeout(function () { shine.remove(); }, 700); 125 }); 126 }); 127 128 // Add keyframe 129 if (!document.getElementById('st-btn-shine-style')) { 130 var style = document.createElement('style'); 131 style.id = 'st-btn-shine-style'; 132 style.textContent = '@keyframes btnShine{0%{left:-100%}100%{left:100%}}'; 133 document.head.appendChild(style); 134 } 135 } 136 137 /* ===== 5. PARALLAX ON HERO ===== */ 138 function parallaxHero() { 139 var hero = document.querySelector('.st-hero'); 140 if (!hero) return; 141 var content = hero.querySelector('.st-hero-content'); 142
143 function update() { 144 var scrolled = window.pageYOffset; 145 if (scrolled < window.innerHeight) { 146 hero.style.backgroundPositionY = (scrolled * 0.4) + 'px'; 147 if (content) { 148 content.style.transform = 'translateY(' + (scrolled * 0.15) + 'px)'; 149 content.style.opacity = 1 - (scrolled / (window.innerHeight * 0.8)); 150 } 151 } 152 } 153 154 // Aplica o estado inicial (scroll = 0) já na carga, para que a posição do 155 // background coincida com a do parallax. Sem isso a imagem fica no "center" 156 // do CSS e "pula" para o topo no primeiro scroll. 157 update(); 158 window.addEventListener('scroll', update); 159 } 160 161 /* ===== 6. GLOW ON HOVER ===== */ 162 function glowOnHover() { 163 var glowEls = document.querySelectorAll('.st-quick-action, .server-card-inner, .ann-link'); 164 glowEls.forEach(function (el) { 165 el.addEventListener('mousemove', function (e) { 166 var rect = el.getBoundingClientRect(); 167 var x = e.clientX - rect.left; 168 var y = e.clientY - rect.top; 169 el.style.setProperty('--glow-x', x + 'px'); 170 el.style.setProperty('--glow-y', y + 'px'); 171 }); 172 }); 173 174 // Add glow style 175 if (!document.getElementById('st-glow-style')) { 176 var style = document.createElement('style'); 177 style.id = 'st-glow-style'; 178 style.textContent = 179 '.st-quick-action:hover,.server-card-inner:hover,.ann-link:hover{' + 180 'background-image:radial-gradient(circle 120px at var(--glow-x,50%) var(--glow-y,50%),rgba(255,255,255,0.08),transparent) !important;}'; 181 document.head.appendChild(style); 182 } 183 } 184 185 /* ===== 7. ANIMATED COUNTERS ===== */ 186 function animateCounters() { 187 var counters = document.querySelectorAll('[data-counter]'); 188 if (!counters.length) return; 189 var observer = new IntersectionObserver(function (entries) { 190 entries.forEach(function (entry) { 191 if (entry.isIntersecting) { 192 var el = entry.target; 193 var target = parseInt(el.dataset.counter); 194 if (isNaN(target)) { observer.unobserve(el); return; } 195 var start = parseInt((el.textContent || '0').replace(/\D/g, '')) || 0; 196 observer.unobserve(el); 197 if (start === target) return; // numero ja renderizado server-side: mantem (sem flash, bom p/ SEO/no-JS) 198 var duration = target > 1000 ? 2000 : 1500; 199 var startTime = null; 200 function step(timestamp) { 201 if (!startTime) startTime = timestamp; 202 var progress = Math.min((timestamp - startTime) / duration, 1); 203 var eased = 1 - Math.pow(1 - progress, 3); 204 var current = Math.floor(start + eased * (target - start)); 205 el.textContent = target >= 1000 ? current.toLocaleString('pt-BR') : current; 206 if (progress < 1) requestAnimationFrame(step); 207 } 208 requestAnimationFrame(step); 209 } 210 }); 211 }, { threshold: 0.5 }); 212 counters.forEach(function (c) { observer.observe(c); }); 213 } 214 215 /* ===== 8. PODIUM CHARACTER LOADER ===== */ 216 function podiumLoader() { 217 if (typeof CharacterPreview === 'undefined') return; 218 var BASE = document.querySelector("link[rel='base']"); 219 if (!BASE) return; 220 BASE = BASE.getAttribute('href'); 221 222 var loaded = {}; 223 224 function loadPodiumSlots(container) { 225 var slots = container.querySelectorAll('.podium-slot'); 226 slots.forEach(function (slot) { 227 var dataEl = slot.querySelector('.podium-data'); 228 var canvas = slot.querySelector('.podium-canvas');
229 if (!dataEl || !canvas || !canvas.id) return; 230 if (loaded[canvas.id]) return; 231 232 var userid = dataEl.dataset.userid; 233 var server = dataEl.dataset.server; 234 if (!userid || !server) return; 235 236 loaded[canvas.id] = true; 237 var preview = new CharacterPreview(canvas.id); 238 239 var xhr = new XMLHttpRequest(); 240 xhr.open('POST', BASE + '/_cdn/widgets/accddtankeiros/users/player.ajax.php'); 241 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 242 xhr.onload = function () { 243 try { 244 var resp = JSON.parse(xhr.responseText); 245 if (resp.success && resp.data && resp.data.style) { 246 preview.render(resp.data.style, resp.data.sex, resp.data.resourceUrl, resp.data.hide, resp.data.styleSex); 247 } 248 } catch (e) {} 249 }; 250 xhr.send('userid=' + userid + '&server=' + server); 251 }); 252 } 253 254 // Load visible podiums 255 setTimeout(function () { 256 document.querySelectorAll('.podium').forEach(function (p) { 257 var pane = p.closest('.tab-pane'); 258 if (!pane || pane.classList.contains('active')) { 259 loadPodiumSlots(p); 260 } 261 }); 262 }, 600); 263 264 // Load on tab change 265 if (window.jQuery) { 266 jQuery(document).on('shown.bs.tab', '[data-toggle="tab"]', function (e) { 267 var target = jQuery(e.target).attr('href'); 268 var podium = document.querySelector(target + ' .podium'); 269 if (podium) loadPodiumSlots(podium); 270 }); 271 } 272 } 273 274 /* ===== 9. NAVBAR SHRINK ON SCROLL ===== */ 275 function navbarShrink() { 276 var header = document.querySelector('.header-modern'); 277 if (!header) return; 278 window.addEventListener('scroll', function () { 279 if (window.pageYOffset > 50) { 280 header.style.padding = '0'; 281 header.style.boxShadow = '0 4px 30px rgba(0,0,0,0.4)'; 282 var logo = header.querySelector('.header-logo'); 283 if (logo) logo.style.height = '36px'; 284 } else { 285 header.style.padding = ''; 286 header.style.boxShadow = ''; 287 var logo = header.querySelector('.header-logo'); 288 if (logo) logo.style.height = ''; 289 } 290 }); 291 } 292 293})();
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.