Widget:Character.Skins

De Wiki Gla
Revisão de 18h34min de 24 de dezembro de 2025 por Gurren1 (discussão | contribs)
Ir para navegação Ir para pesquisar

<script>

   (function initSkinPodiumUI() {
       const podium = document.querySelector('.skins-podium');
       if (!podium || podium.dataset.wired) return;
       podium.dataset.wired = '1';
       // ---------- Tooltip único ----------
       function ensureTip() {
           let tip = document.querySelector('.skin-tooltip');
           if (!tip) {
               tip = document.createElement('div');
               tip.className = 'skin-tooltip';
               tip.setAttribute('role', 'tooltip');
               tip.setAttribute('aria-hidden', 'true');
               tip.style.position = 'fixed';
               tip.style.transform = 'translate(-9999px,-9999px)';
               tip.style.opacity = '0';
               tip.style.transition = 'opacity .12s ease';
               document.body.appendChild(tip);
           }
           return tip;
       }
       const tip = ensureTip();
       let hoveredSlot = null;
       function place(card) {
           if (!card || tip.getAttribute('aria-hidden') === 'true') return;
           tip.style.transform = 'translate(-9999px,-9999px)';
           const tr = tip.getBoundingClientRect();
           // Pega a posição da imagem do tile (piso) para centralizar
           const platformImg = card.querySelector('.podium-platform-top img');
           let platformRect = card.getBoundingClientRect();
           if (platformImg) {
               platformRect = platformImg.getBoundingClientRect();
           } else {
               const platform = card.querySelector('.podium-platform');
               if (platform) {
                   platformRect = platform.getBoundingClientRect();
               }
           }
           // Centraliza horizontalmente baseado na imagem do tile
           let leftPos = Math.round(platformRect.left + (platformRect.width - tr.width) / 2);
           leftPos = Math.max(8, Math.min(leftPos, window.innerWidth - tr.width - 8));
           // Posiciona logo abaixo da imagem do tile
           let top = Math.round(platformRect.bottom + 15);
           if (top + tr.height > window.innerHeight - 8) {
               top = Math.round(platformRect.top - tr.height - 15);
               if (top < 8) top = 8;
           }
           tip.style.transform = `translate(${leftPos}px, ${top}px)`;
       }
       function show(card) {
           const tooltipText = card.getAttribute('data-skin-tooltip') || ;
           tip.innerHTML = tooltipText;
           tip.setAttribute('aria-hidden', 'false');
           place(card);
           tip.style.opacity = '1';
       }
       function hide() {
           tip.setAttribute('aria-hidden', 'true');
           tip.style.opacity = '0';
           tip.style.transform = 'translate(-9999px,-9999px)';
       }
       // Função para restaurar z-index original baseado na posição do slot
       function restoreOriginalZIndex(slot) {
           if (!slot) return;
           const allSlots = Array.from(podium.querySelectorAll('.podium-slot'));
           const slotIndex = allSlots.indexOf(slot);
           // Z-index invertido: esquerda (0) = mais alto, direita = mais baixo
           const originalZIndex = allSlots.length - slotIndex;
           const originalSpriteZIndex = (allSlots.length - slotIndex) * 1000;
           slot.style.zIndex = originalZIndex.toString();
           const spriteContainer = slot.querySelector('.podium-sprite-container');
           if (spriteContainer) spriteContainer.style.zIndex = originalSpriteZIndex.toString();
       }
       function setHovered(card) {
           if (hoveredSlot === card) return;
           if (hoveredSlot) {
               hoveredSlot.classList.remove('hovered');
               restoreOriginalZIndex(hoveredSlot);
           }
           podium.classList.remove('hovering');
           podium.querySelectorAll('.podium-slot.dim').forEach(n => n.classList.remove('dim'));
           if (!card) {
               hoveredSlot = null;
               hide();
               return;
           }
           hoveredSlot = card;
           hoveredSlot.classList.add('hovered');
           podium.classList.add('hovering');
           podium.querySelectorAll('.podium-slot').forEach(n => {
               if (n !== hoveredSlot) n.classList.add('dim');
           });
           // Qualquer skin com hover fica acima de tudo
           card.style.zIndex = '9999';
           const spriteContainer = card.querySelector('.podium-sprite-container');
           if (spriteContainer) spriteContainer.style.zIndex = '9999';
           show(card);
       }
       // Função para verificar se o pixel na posição do mouse é transparente
       function isPixelTransparent(img, x, y) {
           if (!img.complete || img.naturalWidth === 0) return true;
           try {
               const canvas = document.createElement('canvas');
               canvas.width = img.naturalWidth;
               canvas.height = img.naturalHeight;
               const ctx = canvas.getContext('2d');
               ctx.drawImage(img, 0, 0);
               const rect = img.getBoundingClientRect();
               const scaleX = img.naturalWidth / rect.width;
               const scaleY = img.naturalHeight / rect.height;
               const imgX = Math.floor((x - rect.left) * scaleX);
               const imgY = Math.floor((y - rect.top) * scaleY);
               if (imgX < 0 || imgX >= img.naturalWidth || imgY < 0 || imgY >= img.naturalHeight) {
                   return true;
               }
               const pixelData = ctx.getImageData(imgX, imgY, 1, 1).data;
               return pixelData[3] < 10;
           } catch (e) {
               return false;
           }
       }
       // ---------- Abrir YouTube (sem duplicar) ----------
       podium.addEventListener('click', (ev) => {
           const card = ev.target?.closest('.podium-slot[data-youtube]');
           if (!card) return;
           const url = (card.dataset.youtube || ).trim();
           if (!url) return;
           if (card.dataset._opening === '1') return;
           card.dataset._opening = '1';
           ev.preventDefault();
           ev.stopPropagation();
           ev.stopImmediatePropagation();
           try { window.open(url, '_blank', 'noopener,noreferrer'); }
           catch (e) { location.href = url; }
           setTimeout(() => { delete card.dataset._opening; }, 500);
       }, { capture: true });
       podium.addEventListener('keydown', (ev) => {
           if (ev.key !== 'Enter' && ev.key !== ' ') return;
           const card = ev.target?.closest('.podium-slot[data-youtube]');
           if (!card) return;
           const url = (card.dataset.youtube || ).trim();
           if (!url) return;
           if (card.dataset._opening === '1') return;
           card.dataset._opening = '1';
           ev.preventDefault();
           ev.stopPropagation();
           ev.stopImmediatePropagation();
           try { window.open(url, '_blank', 'noopener,noreferrer'); }
           catch (e) { location.href = url; }
           setTimeout(() => { delete card.dataset._opening; }, 500);
       }, { capture: true });
       // ---------- Hitbox pixel-perfect de hover ----------
       const slots = podium.querySelectorAll('.podium-slot');
       slots.forEach(slot => {
           const spriteImg = slot.querySelector('.podium-sprite img');
           if (spriteImg) {
               spriteImg.addEventListener('pointerenter', (ev) => {
                   if (!slot.hasAttribute('data-skin-tooltip')) return;
                   if (!isPixelTransparent(spriteImg, ev.clientX, ev.clientY)) {
                       setHovered(slot);
                   }
               }, { passive: true });
               spriteImg.addEventListener('pointermove', (ev) => {
                   if (!slot.hasAttribute('data-skin-tooltip')) return;
                   if (isPixelTransparent(spriteImg, ev.clientX, ev.clientY)) {
                       if (hoveredSlot === slot) setHovered(null);
                   } else {
                       if (hoveredSlot !== slot) setHovered(slot);
                   }
               }, { passive: true });
               spriteImg.addEventListener('pointerleave', (ev) => {
                   const toCard = ev.relatedTarget?.closest?.('.podium-slot');
                   if (toCard && podium.contains(toCard)) {
                       const otherImg = toCard.querySelector('.podium-sprite img');
                       if (otherImg && ev.relatedTarget && !isPixelTransparent(otherImg, ev.clientX, ev.clientY)) {
                           return;
                       }
                   }
                   setHovered(null);
               }, { passive: true });
           }
       });
       podium.addEventListener('pointerleave', () => { setHovered(null); }, { passive: true });
       window.addEventListener('scroll', () => { if (hoveredSlot) place(hoveredSlot); }, true);
       window.addEventListener('resize', () => { if (hoveredSlot) place(hoveredSlot); });
   })();

</script> <style>

   .skins-podium {
       display: flex;
       align-items: flex-end;
       justify-content: center;
       gap: 30px;
       padding: 40px 20px;
   }
   .podium-slot {
       position: relative;
       display: flex;
       flex-direction: column;
       align-items: center;
       justify-content: flex-end;
       cursor: pointer;
       transition: filter 0.14s ease, box-shadow 0.14s ease;
   }
   /* Z-index INVERTIDO: sprites da direita passam por trás das da esquerda */
   .podium-slot:nth-child(1) {
       z-index: 4;
   }
   .podium-slot:nth-child(2) {
       z-index: 3;
   }
   .podium-slot:nth-child(3) {
       z-index: 2;
   }
   .podium-slot:nth-child(4) {
       z-index: 1;
   }
   .podium-slot:nth-child(5) {
       z-index: 1;
   }
   /* Z-index INVERTIDO: sprites da direita passam por trás das da esquerda */
   .podium-slot:nth-child(1) .podium-sprite-container {
       z-index: 4000;
   }
   .podium-slot:nth-child(2) .podium-sprite-container {
       z-index: 3000;
   }
   .podium-slot:nth-child(3) .podium-sprite-container {
       z-index: 2000;
   }
   .podium-slot:nth-child(4) .podium-sprite-container {
       z-index: 1000;
   }
   .podium-slot:nth-child(5) .podium-sprite-container {
       z-index: 1000;
   }
   /* Hitbox baseada na imagem, não no container */
   .podium-slot>* {
       pointer-events: none;
   }
   .podium-sprite img {
       pointer-events: auto;
   }
   .podium-sprite-container,
   .podium-sprite {
       pointer-events: none;
   }
   .podium-platform,
   .podium-platform-top,
   .podium-platform-top img {
       pointer-events: none !important;
   }
   .podium-sprite-container {
       position: relative;
       z-index: 10;
       display: flex;
       align-items: flex-end;
       justify-content: center;
       filter: drop-shadow(0 6px 20px rgba(0, 0, 0, 0.5));
       transform: none !important;
       flex-shrink: 0;
       width: 100%;
   }
   .podium-sprite {
       display: block;
       position: relative;
       transform: none !important;
       flex-shrink: 0;
   }
   .podium-sprite img {
       width: auto;
       height: auto;
       max-width: none;
       max-height: none;
       image-rendering: pixelated;
       image-rendering: -moz-crisp-edges;
       image-rendering: -webkit-optimize-contrast;
       image-rendering: crisp-edges;
       display: block;
       position: relative;
       z-index: 100 !important;
       transform: none !important;
       flex-shrink: 0;
   }
   .podium-platform {
       position: absolute;
       width: auto;
       height: auto;
       bottom: -15px;
       right: -25px;
       z-index: 0 !important;
   }
   .podium-platform-top {
       position: absolute;
       width: auto;
       height: auto;
       transform-origin: center bottom;
       transform: rotateX(15deg);
       z-index: -1 !important;
   }
   .podium-platform-top img {
       display: block;
       width: auto;
       height: auto;
       max-width: none;
       max-height: none;
       image-rendering: pixelated;
       image-rendering: -moz-crisp-edges;
       image-rendering: -webkit-optimize-contrast;
       image-rendering: crisp-edges;
       position: relative;
       z-index: 1;
       border: none !important;
       outline: none;
       box-shadow: none;
       filter: drop-shadow(3px 3px 0 rgba(0, 0, 0, 0.5));
   }
   .skins-podium.hovering .podium-slot.dim {
       filter: brightness(.55) saturate(.85);
       transition: filter .14s ease;
   }
   .skins-podium.hovering .podium-slot.hovered {
       filter: none;
   }
   .skins-podium.hovering .podium-slot.hovered .podium-platform-top {
       box-shadow:
           0 0 0 2px rgba(255, 255, 255, .12),
           0 10px 28px rgba(0, 0, 0, .45);
   }
   .skins-podium.hovering .podium-slot.hovered .podium-platform-top img {
       box-shadow: none !important;
       filter: drop-shadow(3px 3px 0 rgba(0, 0, 0, 0.5)) !important;
   }
   .skin-tooltip {
       position: fixed;
       z-index: 9999;
       left: 0;
       top: 0;
       pointer-events: none;
       padding: 10px 12px;
       border-radius: 8px;
       background: rgba(28, 28, 34, .98);
       color: #eaeaea;
       font-size: 13px;
       line-height: 1.4;
       box-shadow: 0 8px 24px rgba(0, 0, 0, .5), inset 0 0 0 1px rgba(255, 255, 255, .06);
       transform: translate(-9999px, -9999px);
       opacity: 0;
       transition: opacity .15s ease;
       text-align: center;
       white-space: normal;
       max-width: 280px;
       min-width: 200px;
   }
   .skin-tooltip b {
       color: #fff;
   }
   .podium-slot.is-clickable {
       cursor: pointer;
   }
   .podium-slot.is-clickable:focus {
       outline: 2px solid #156bc7;
       outline-offset: 2px;
   }
   @media (max-width: 1024px) {
       .skins-podium {
           gap: 24px;
       }
   }
   @media (max-width: 768px) {
       .skins-podium {
           flex-wrap: wrap;
           gap: 20px;
       }
   }

</style>