Mudanças entre as edições de "Widget:Teste"
Ir para navegação
Ir para pesquisar
m |
m |
||
| Linha 1: | Linha 1: | ||
<style> | |||
.utab { | |||
font-family: "Segoe UI", Arial, sans-serif; | |||
color: #e2ecff; | |||
padding: 24px; | |||
max-width: 980px; | |||
margin: 24px auto; | |||
} | |||
.utab__tabs { | |||
display: flex; | |||
flex-wrap: wrap; | |||
gap: 8px; | |||
margin-bottom: 0; | |||
border-bottom: 1px solid #203c5f; | |||
} | |||
.utab__tab { | |||
display: inline-flex; | |||
align-items: center; | |||
border: 1px solid #274a74; | |||
border-bottom: none; | |||
background: #0f1b2d; | |||
padding: 10px 14px; | |||
border-radius: 10px 10px 0 0; | |||
cursor: pointer; | |||
font-weight: 600; | |||
color: #cfe1ff; | |||
transition: all 0.2s ease; | |||
} | |||
} | |||
.utab__tab:hover { | |||
border-color: #4a86d8; | |||
color: #ffffff; | |||
} | |||
} | |||
.utab__tab.is-active { | |||
background: #2e7dd7; | |||
border-color: #2e7dd7; | |||
color: #ffffff; | |||
} | position: relative; | ||
top: 1px; | |||
} | |||
.utab__tab.is-active::after { | |||
content: ""; | |||
position: absolute; | |||
} | left: 0; | ||
right: 0; | |||
bottom: -2px; | |||
height: 2px; | |||
background: #0f1b2d; | |||
} | |||
.utab__tab:focus-visible, | |||
.utab__levelBtn:focus-visible { | |||
outline: 2px solid rgba(46, 125, 215, 0.4); | |||
outline-offset: 2px; | |||
. | } | ||
. | |||
} | |||
.utab__section { | |||
display: none; | |||
} | |||
} | |||
. | .utab__section.is-active { | ||
display: block; | |||
} | } | ||
# | .utab__panel { | ||
background: #0f1b2d; | |||
border-radius: 0 14px 14px 14px; | |||
} | padding: 20px; | ||
border: 1px solid #203c5f; | |||
box-shadow: 0 10px 24px rgba(7, 14, 26, 0.35); | |||
} | |||
.utab__levels { | |||
display: flex; | |||
flex-wrap: wrap; | |||
gap: 8px; | |||
margin-bottom: 16px; | |||
} | |||
} | |||
.utab__levelBtn { | |||
border: 1px solid #274a74; | |||
} | background: #13243a; | ||
padding: 6px 12px; | |||
border-radius: 10px; | |||
font-weight: 600; | |||
color: #cfe1ff; | |||
cursor: pointer; | |||
transition: all 0.2s ease; | |||
} | |||
.utab__levelBtn:hover { | |||
border-color: #4a86d8; | |||
color: #ffffff; | |||
} | } | ||
.utab__levelBtn.is-active { | |||
background: #2e7dd7; | |||
} | border-color: #2e7dd7; | ||
color: #ffffff; | |||
} | |||
.utab__display { | |||
display: grid; | |||
grid-template-columns: minmax(160px, 220px) 1fr; | |||
gap: 18px; | |||
. | align-items: start; | ||
} | |||
} | |||
.utab__display.is-image-empty { | |||
grid-template-columns: 1fr; | |||
} | |||
} | |||
.utab__display.is-fading { | |||
animation: utabFade 0.25s ease; | |||
} | } | ||
.utab__image { | |||
border-radius: 12px; | |||
border: 1px solid #203c5f; | |||
# | background: #0b1422; | ||
padding: 10px; | |||
} | } | ||
.utab__image img { | |||
display: block; | |||
} | width: 100%; | ||
height: auto; | |||
border-radius: 8px; | |||
} | |||
.utab__image.is-empty { | |||
display: none; | |||
} | |||
} | |||
.utab__stats { | |||
display: grid; | |||
gap: 10px; | |||
color: #dbe7ff; | |||
font-size: 14px; | |||
} | |||
} | |||
.utab__stat { | |||
background: #13243a; | |||
border: 1px solid #274a74; | |||
} | border-radius: 10px; | ||
padding: 10px 12px; | |||
} | |||
.utab__statTitle { | |||
font-weight: 700; | |||
} | color: #8bb8ff; | ||
} | |||
.utab__statList { | |||
margin: 6px 0 0; | |||
} | padding-left: 18px; | ||
display: grid; | |||
gap: 2px; | |||
list-style: disc; | |||
list-style-position: outside; | |||
} | |||
.utab__statList li { | |||
display: list-item; | |||
} | text-align: left; | ||
} | |||
.utab__costRow { | |||
position: relative; | |||
} | |||
} | |||
.utab__costBerry, | |||
.utab__costGems, | |||
.utab__costPoints { | |||
} | display: inline-flex; | ||
align-items: center; | |||
gap: 6px; | |||
font-weight: 700; | |||
line-height: 1.1; | |||
font-size: 15px; | |||
} | |||
.utab__costBerry { | |||
color: #ffd166; | |||
} | |||
} | |||
.utab__costGems { | |||
color: #57d889; | |||
} | } | ||
.utab__costPoints { | |||
color: #a6b0bf; | |||
} | } | ||
.utab__costIcon { | |||
display: none; | |||
} | |||
} | |||
.utab__costBerry .utab__costIcon, | |||
.utab__costGems .utab__costIcon, | |||
.utab__costPoints .utab__costIcon, | |||
. | .utab__costBerry .utab__costText, | ||
. | .utab__costGems .utab__costText, | ||
.utab__costPoints .utab__costText { | |||
transform: none; | |||
} | } | ||
. | .utab__level--source { | ||
display: none; | |||
} | } | ||
@keyframes utabFade { | |||
from { | |||
opacity: 0; | |||
transform: translateY(4px); | |||
} | } | ||
to { | |||
opacity: 1; | |||
} | transform: translateY(0); | ||
} | |||
} | |||
@media (max-width: 720px) { | |||
.utab { | |||
padding: 16px; | |||
} | |||
} | |||
. | .utab__display { | ||
grid-template-columns: 1fr; | |||
} | |||
} | |||
</style> | |||
<div class="utab"> | |||
<section class="utab__section" data-tab="Designer"> | |||
<div class="utab__level" data-level="1"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Designer_lvl1.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>1 pilar de artefato disponível</li> | |||
<li>27 símbolos disponíveis</li> | |||
<li>1 plano de fundo disponível</li> | |||
<li>6 cores disponíveis</li> | |||
<li>2% de EXP</li> | |||
<li>4% de sorte</li> | |||
<li>5% de pontos de aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="2"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Designer_lvl2.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>2 pilares de artefato disponíveis</li> | |||
<li>9 planos de fundo disponíveis</li> | |||
<li>47 símbolos disponíveis</li> | |||
<li>12 cores disponíveis</li> | |||
<li>4% de EXP</li> | |||
<li>9% de sorte</li> | |||
<li>12% de pontos de aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="3"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Designer_lvl3.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>2 pilares de artefato disponíveis</li> | |||
<li>34 planos de fundo disponíveis</li> | |||
<li>72 símbolos disponíveis</li> | |||
<li>30 cores disponíveis</li> | |||
<li>6% de EXP</li> | |||
<li>15% de sorte</li> | |||
<li>22% de pontos de aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="4"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Designer_lvl4.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>3 pilares de artefato disponíveis</li> | |||
<li>34 planos de fundo disponíveis</li> | |||
<li>92 símbolos disponíveis</li> | |||
<li>30 cores disponíveis</li> | |||
<li>8% de EXP</li> | |||
<li>22% de sorte</li> | |||
<li>35% de pontos de aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="5"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Designer_lvl5.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>4 pilares de artefato disponíveis</li> | |||
<li>34 planos de fundo disponíveis</li> | |||
<li>112 símbolos disponíveis</li> | |||
<li>30 cores disponíveis</li> | |||
<li>10% de EXP</li> | |||
<li>30% de sorte</li> | |||
<li>50% de pontos de aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</section> | |||
<section class="utab__section" data-tab="Cofre"> | |||
<div class="utab__level" data-level="1"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cofre_lvl1.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>10% de bônus pra aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="2"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cofre_lvl2.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>+ 100 espaços extra no cofre</li> | |||
<li>25% de bônus pra aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="3"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cofre_lvl3.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>+ 200 espaços extra no cofre</li> | |||
<li>45% de bônus pra aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="4"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cofre_lvl4.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>+ 300 espaços extra no cofre</li> | |||
<li>75% de bônus pra aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="5"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cofre_lvl5.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>+ 400 espaços extra no cofre</li> | |||
<li>100% de bônus pra aliança</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</section> | |||
<section class="utab__section" data-tab="Salão Principal"> | |||
<div class="utab__level" data-level="1"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaoPrincipal_lvl1.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 1</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="2"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaoPrincipal_lvl2.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 2</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="3"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaoPrincipal_lvl3.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 3</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="4"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaoPrincipal_lvl4.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 4</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="5"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaoPrincipal_lvl5.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 5</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</section> | |||
<section class="utab__section" data-tab="Quartos"> | |||
<div class="utab__level" data-level="1"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Quartos_lvl1.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 1</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="2"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Quartos_lvl2.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 2</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="3"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Quartos_lvl3.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 3</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="4"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Quartos_lvl4.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 4</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="5"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Quartos_lvl5.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 5</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</section> | |||
<section class="utab__section" data-tab="Sala de Guerra"> | |||
<div class="utab__level" data-level="1"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaDeGuerra_lvl1.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 1</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="2"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaDeGuerra_lvl2.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 2</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="3"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaDeGuerra_lvl3.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 3</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="4"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaDeGuerra_lvl4.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 4</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="5"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:SalaDeGuerra_lvl5.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 5</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</section> | |||
<section class="utab__section" data-tab="Treinamento"> | |||
<div class="utab__level" data-level="1"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Treinamento_lvl1.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 1</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="2"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Treinamento_lvl2.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 2</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="3"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Treinamento_lvl3.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 3</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="4"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Treinamento_lvl4.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 4</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="5"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Treinamento_lvl5.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 5</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</section> | |||
<section class="utab__section" data-tab="Ferreiro"> | |||
<div class="utab__level" data-level="1"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Ferreiro_lvl1.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 1</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="2"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Ferreiro_lvl2.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 2</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="3"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Ferreiro_lvl3.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 3</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="4"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Ferreiro_lvl4.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 4</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="5"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Ferreiro_lvl5.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 5</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</section> | |||
<section class="utab__section" data-tab="Cozinha"> | |||
<div class="utab__level" data-level="1"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cozinha_lvl1.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 1</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="2"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cozinha_lvl2.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 2</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="3"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cozinha_lvl3.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 3</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="4"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cozinha_lvl4.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 4</li> | |||
</ul> | |||
</div> | |||
</div> | |||
<div class="utab__level" data-level="5"> | |||
<div class="utab__content"> | |||
<div class="utab__mediaImage">[[File:Cozinha_lvl5.png|200px]]</div> | |||
<ul class="utab__statList"> | |||
<li>Descrição do nível 5</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</section> | |||
</div> | |||
<script> | |||
function handleArrowNavigation(event, buttons, activate) { | |||
} | const keys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"]; | ||
if (!keys.includes(event.key)) { | |||
return; | |||
} | |||
event.preventDefault(); | |||
const currentIndex = buttons.findIndex((button) => button === document.activeElement); | |||
if (currentIndex === -1) { | |||
} | return; | ||
} | |||
let nextIndex = currentIndex; | |||
if (event.key === "Home") { | |||
nextIndex = 0; | |||
} | } else if (event.key === "End") { | ||
nextIndex = buttons.length - 1; | |||
} else if (event.key === "ArrowLeft" || event.key === "ArrowUp") { | |||
nextIndex = (currentIndex - 1 + buttons.length) % buttons.length; | |||
} else if (event.key === "ArrowRight" || event.key === "ArrowDown") { | |||
nextIndex = (currentIndex + 1) % buttons.length; | |||
} | |||
activate(nextIndex, true); | |||
} | |||
} | |||
. | function triggerFade(element) { | ||
element.classList.remove("is-fading"); | |||
} | void element.offsetWidth; | ||
element.classList.add("is-fading"); | |||
} | |||
. | function hasWikitext(value) { | ||
return typeof value === "string" && (value.includes("[[") || value.includes("{{")); | |||
} | } | ||
function parseWikitextCached(raw, cacheKey, target) { | |||
if (!raw || !hasWikitext(raw)) { | |||
return Promise.resolve(raw); | |||
} | |||
} | if (target[cacheKey]) { | ||
return Promise.resolve(target[cacheKey]); | |||
} | |||
if (!window.mw || !mw.Api) { | |||
return Promise.resolve(raw); | |||
} | |||
const api = new mw.Api(); | |||
return api | |||
.post({ | |||
action: "parse", | |||
text: raw, | |||
contentmodel: "wikitext", | |||
} | prop: "text", | ||
formatversion: 2 | |||
}) | |||
.then((response) => { | |||
const html = response?.parse?.text || response?.parse?.text?.["*"] || raw; | |||
target[cacheKey] = html; | |||
return html; | |||
}) | |||
.catch(() => raw); | |||
} | |||
const upgradeCosts = [ | |||
{ level: 1, berries: "50.000", gems: "10", points: "400" }, | |||
} | { level: 2, berries: "250.000", gems: "10", points: "1.500" }, | ||
{ level: 3, berries: "400.000", gems: "20", points: "3.000" }, | |||
{ level: 4, berries: "1.000.000", gems: "50", points: "12.500" }, | |||
{ level: 5, berries: "1.800.000", gems: "90", points: "28.000" } | |||
]; | |||
function buildLevelUI(section, tabLabel) { | |||
const levelElements = Array.from(section.querySelectorAll(".utab__level")); | |||
const levels = levelElements.map((levelElement, index) => { | |||
const levelNumber = levelElement.dataset.level || String(index + 1); | |||
const contentElement = levelElement.querySelector(".utab__content") || levelElement; | |||
const rawHtml = contentElement.innerHTML.trim(); | |||
const contentWrapper = document.createElement("div"); | |||
contentWrapper.innerHTML = rawHtml; | |||
const mediaImage = contentWrapper.querySelector(".utab__mediaImage"); | |||
const imageHtml = mediaImage ? mediaImage.innerHTML.trim() : ""; | |||
if (mediaImage) { | |||
mediaImage.remove(); | |||
} | |||
const statsHtml = contentWrapper.innerHTML.trim(); | |||
return { | |||
level: levelNumber, | |||
imageHtml, | |||
statsHtml | |||
}; | |||
}); | |||
levelElements.forEach((levelElement) => { | |||
levelElement.classList.add("utab__level--source"); | |||
}); | |||
const nav = document.createElement("div"); | |||
nav.className = "utab__levels"; | |||
nav.setAttribute("role", "tablist"); | |||
nav.setAttribute("aria-label", `Níveis de ${tabLabel}`); | |||
const display = document.createElement("div"); | |||
display.className = "utab__display"; | |||
const imageWrap = document.createElement("div"); | |||
imageWrap.className = "utab__image"; | |||
const stats = document.createElement("div"); | |||
stats.className = "utab__stats"; | |||
display.appendChild(imageWrap); | |||
display.appendChild(stats); | |||
. | const buttons = levels.map((level, index) => { | ||
. | const button = document.createElement("button"); | ||
button.type = "button"; | |||
button.className = "utab__levelBtn"; | |||
} | button.textContent = `Nv ${level.level}`; | ||
button.setAttribute("role", "tab"); | |||
button.setAttribute("aria-selected", "false"); | |||
button.setAttribute("tabindex", "-1"); | |||
button.addEventListener("click", () => activateLevel(index, true)); | |||
button.addEventListener("keydown", (event) => handleArrowNavigation(event, buttons, activateLevel)); | |||
nav.appendChild(button); | |||
return button; | |||
}); | |||
. | section.prepend(display); | ||
section.prepend(nav); | |||
let renderToken = 0; | |||
function activateLevel(index, shouldFocus) { | |||
if (!levels.length) { | |||
} | return; | ||
} | |||
. | const safeIndex = Math.max(0, Math.min(index, levels.length - 1)); | ||
const current = levels[safeIndex]; | |||
const token = ++renderToken; | |||
buttons.forEach((button, buttonIndex) => { | |||
const isActive = buttonIndex === safeIndex; | |||
button.classList.toggle("is-active", isActive); | |||
button.setAttribute("aria-selected", isActive ? "true" : "false"); | |||
button.setAttribute("tabindex", isActive ? "0" : "-1"); | |||
}); | |||
} | |||
if (current.imageHtml) { | |||
imageWrap.innerHTML = current.imageHtml; | |||
imageWrap.classList.remove("is-empty"); | |||
display.classList.remove("is-image-empty"); | |||
} else { | |||
imageWrap.innerHTML = ""; | |||
imageWrap.classList.add("is-empty"); | |||
display.classList.add("is-image-empty"); | |||
} | |||
} | |||
const levelNumber = Number(current.level); | |||
const cost = upgradeCosts.find((item) => item.level === levelNumber); | |||
const costHtml = cost | |||
? ` | |||
<div class="utab__stat"> | |||
<div class="utab__statTitle">Custo do upgrade</div> | |||
<ul class="utab__statList"> | |||
<li class="utab__costRow"> | |||
<span class="utab__costBerry"> | |||
<span class="utab__costText">${cost.berries} berries</span> | |||
</span> | |||
</li> | |||
${cost.gems ? ` | |||
<li class="utab__costRow"> | |||
<span class="utab__costGems"> | |||
<span class="utab__costText">${cost.gems} gemas</span> | |||
</span> | |||
</li> | |||
` : ""} | |||
<li class="utab__costRow"> | |||
<span class="utab__costPoints"> | |||
<span class="utab__costText">${cost.points} pontos</span> | |||
</span> | |||
</li> | |||
</ul> | |||
</div> | |||
` | |||
: ""; | |||
stats.innerHTML = `${current.statsHtml}${costHtml}`; | |||
triggerFade(display); | |||
const shouldParse = | |||
(current.imageHtml && hasWikitext(current.imageHtml)) || | |||
(current.statsHtml && hasWikitext(current.statsHtml)); | |||
. | |||
. | if (shouldParse) { | ||
Promise.all([ | |||
parseWikitextCached(current.imageHtml, "parsedImageHtml", current), | |||
} | parseWikitextCached(current.statsHtml, "parsedStatsHtml", current) | ||
]).then(([parsedImage, parsedStats]) => { | |||
if (renderToken !== token) { | |||
return; | |||
} | |||
if (parsedImage && parsedImage !== current.imageHtml) { | |||
imageWrap.innerHTML = parsedImage; | |||
imageWrap.classList.remove("is-empty"); | |||
display.classList.remove("is-image-empty"); | |||
} | |||
if (parsedStats && parsedStats !== current.statsHtml) { | |||
stats.innerHTML = `${parsedStats}${costHtml}`; | |||
} | |||
}); | |||
} | |||
if (shouldFocus) { | |||
buttons[safeIndex].focus(); | |||
} | |||
} | } | ||
return { | |||
activateLevel | |||
}; | |||
} | |||
} | |||
function initTabber(widget) { | |||
const sections = Array.from(widget.querySelectorAll(".utab__section")); | |||
if (!sections.length) { | |||
return; | |||
} | |||
} | |||
. | const tabs = document.createElement("div"); | ||
tabs.className = "utab__tabs"; | |||
tabs.setAttribute("role", "tablist"); | |||
tabs.setAttribute("aria-label", "Categorias"); | |||
const tabButtons = []; | |||
const sectionStates = []; | |||
sections.forEach((section, index) => { | |||
const label = section.dataset.tab || `Categoria ${index + 1}`; | |||
section.classList.add("utab__panel"); | |||
. | section.setAttribute("role", "tabpanel"); | ||
section.setAttribute("aria-label", label); | |||
. | const button = document.createElement("button"); | ||
. | button.type = "button"; | ||
button.className = "utab__tab"; | |||
button.textContent = label; | |||
button.setAttribute("role", "tab"); | |||
button.setAttribute("aria-selected", "false"); | |||
button.setAttribute("tabindex", "-1"); | |||
button.addEventListener("click", () => activateTab(index, true)); | |||
button.addEventListener("keydown", (event) => handleArrowNavigation(event, tabButtons, activateTab)); | |||
. | tabs.appendChild(button); | ||
tabButtons.push(button); | |||
sectionStates.push(buildLevelUI(section, label)); | |||
} | }); | ||
. | widget.prepend(tabs); | ||
. | function activateTab(index, shouldFocus) { | ||
. | const safeIndex = Math.max(0, Math.min(index, sections.length - 1)); | ||
sections.forEach((section, sectionIndex) => { | |||
const isActive = sectionIndex === safeIndex; | |||
section.classList.toggle("is-active", isActive); | |||
. | section.setAttribute("aria-hidden", isActive ? "false" : "true"); | ||
. | const tabButton = tabButtons[sectionIndex]; | ||
tabButton.classList.toggle("is-active", isActive); | |||
} | tabButton.setAttribute("aria-selected", isActive ? "true" : "false"); | ||
tabButton.setAttribute("tabindex", isActive ? "0" : "-1"); | |||
}); | |||
. | sectionStates[safeIndex]?.activateLevel(0, false); | ||
if (shouldFocus) { | |||
tabButtons[safeIndex].focus(); | |||
} | } | ||
} | |||
activateTab(0, false); | |||
} | |||
} | |||
function initTabbers() { | |||
document.querySelectorAll(".utab").forEach(initTabber); | |||
} | } | ||
if (document.readyState === "loading") { | |||
document.addEventListener("DOMContentLoaded", initTabbers); | |||
} else { | |||
initTabbers(); | |||
} | } | ||
</script> | |||
/ | |||
Edição das 16h57min de 7 de fevereiro de 2026
<style>
.utab {
font-family: "Segoe UI", Arial, sans-serif;
color: #e2ecff;
padding: 24px;
max-width: 980px;
margin: 24px auto;
}
.utab__tabs {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 0;
border-bottom: 1px solid #203c5f;
}
.utab__tab {
display: inline-flex;
align-items: center;
border: 1px solid #274a74;
border-bottom: none;
background: #0f1b2d;
padding: 10px 14px;
border-radius: 10px 10px 0 0;
cursor: pointer;
font-weight: 600;
color: #cfe1ff;
transition: all 0.2s ease;
}
.utab__tab:hover {
border-color: #4a86d8;
color: #ffffff;
}
.utab__tab.is-active {
background: #2e7dd7;
border-color: #2e7dd7;
color: #ffffff;
position: relative;
top: 1px;
}
.utab__tab.is-active::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -2px;
height: 2px;
background: #0f1b2d;
}
.utab__tab:focus-visible,
.utab__levelBtn:focus-visible {
outline: 2px solid rgba(46, 125, 215, 0.4);
outline-offset: 2px;
}
.utab__section {
display: none;
}
.utab__section.is-active {
display: block;
}
.utab__panel {
background: #0f1b2d;
border-radius: 0 14px 14px 14px;
padding: 20px;
border: 1px solid #203c5f;
box-shadow: 0 10px 24px rgba(7, 14, 26, 0.35);
}
.utab__levels {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
}
.utab__levelBtn {
border: 1px solid #274a74;
background: #13243a;
padding: 6px 12px;
border-radius: 10px;
font-weight: 600;
color: #cfe1ff;
cursor: pointer;
transition: all 0.2s ease;
}
.utab__levelBtn:hover {
border-color: #4a86d8;
color: #ffffff;
}
.utab__levelBtn.is-active {
background: #2e7dd7;
border-color: #2e7dd7;
color: #ffffff;
}
.utab__display {
display: grid;
grid-template-columns: minmax(160px, 220px) 1fr;
gap: 18px;
align-items: start;
}
.utab__display.is-image-empty {
grid-template-columns: 1fr;
}
.utab__display.is-fading {
animation: utabFade 0.25s ease;
}
.utab__image {
border-radius: 12px;
border: 1px solid #203c5f;
background: #0b1422;
padding: 10px;
}
.utab__image img {
display: block;
width: 100%;
height: auto;
border-radius: 8px;
}
.utab__image.is-empty {
display: none;
}
.utab__stats {
display: grid;
gap: 10px;
color: #dbe7ff;
font-size: 14px;
}
.utab__stat {
background: #13243a;
border: 1px solid #274a74;
border-radius: 10px;
padding: 10px 12px;
}
.utab__statTitle {
font-weight: 700;
color: #8bb8ff;
}
.utab__statList {
margin: 6px 0 0;
padding-left: 18px;
display: grid;
gap: 2px;
list-style: disc;
list-style-position: outside;
}
.utab__statList li {
display: list-item;
text-align: left;
}
.utab__costRow {
position: relative;
}
.utab__costBerry,
.utab__costGems,
.utab__costPoints {
display: inline-flex;
align-items: center;
gap: 6px;
font-weight: 700;
line-height: 1.1;
font-size: 15px;
}
.utab__costBerry {
color: #ffd166;
}
.utab__costGems {
color: #57d889;
}
.utab__costPoints {
color: #a6b0bf;
}
.utab__costIcon {
display: none;
}
.utab__costBerry .utab__costIcon,
.utab__costGems .utab__costIcon,
.utab__costPoints .utab__costIcon,
.utab__costBerry .utab__costText,
.utab__costGems .utab__costText,
.utab__costPoints .utab__costText {
transform: none;
}
.utab__level--source {
display: none;
}
@keyframes utabFade {
from {
opacity: 0;
transform: translateY(4px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 720px) {
.utab {
padding: 16px;
}
.utab__display {
grid-template-columns: 1fr;
}
}
</style>
<section class="utab__section" data-tab="Designer">
- 1 pilar de artefato disponível
- 27 símbolos disponíveis
- 1 plano de fundo disponível
- 6 cores disponíveis
- 2% de EXP
- 4% de sorte
- 5% de pontos de aliança
- 2 pilares de artefato disponíveis
- 9 planos de fundo disponíveis
- 47 símbolos disponíveis
- 12 cores disponíveis
- 4% de EXP
- 9% de sorte
- 12% de pontos de aliança
- 2 pilares de artefato disponíveis
- 34 planos de fundo disponíveis
- 72 símbolos disponíveis
- 30 cores disponíveis
- 6% de EXP
- 15% de sorte
- 22% de pontos de aliança
- 3 pilares de artefato disponíveis
- 34 planos de fundo disponíveis
- 92 símbolos disponíveis
- 30 cores disponíveis
- 8% de EXP
- 22% de sorte
- 35% de pontos de aliança
- 4 pilares de artefato disponíveis
- 34 planos de fundo disponíveis
- 112 símbolos disponíveis
- 30 cores disponíveis
- 10% de EXP
- 30% de sorte
- 50% de pontos de aliança
</section> <section class="utab__section" data-tab="Cofre">
- 10% de bônus pra aliança
- + 100 espaços extra no cofre
- 25% de bônus pra aliança
- + 200 espaços extra no cofre
- 45% de bônus pra aliança
- + 300 espaços extra no cofre
- 75% de bônus pra aliança
- + 400 espaços extra no cofre
- 100% de bônus pra aliança
</section> <section class="utab__section" data-tab="Salão Principal">
- Descrição do nível 1
- Descrição do nível 2
- Descrição do nível 3
- Descrição do nível 4
- Descrição do nível 5
</section> <section class="utab__section" data-tab="Quartos">
- Descrição do nível 1
- Descrição do nível 2
- Descrição do nível 3
- Descrição do nível 4
- Descrição do nível 5
</section> <section class="utab__section" data-tab="Sala de Guerra">
- Descrição do nível 1
- Descrição do nível 2
- Descrição do nível 3
- Descrição do nível 4
- Descrição do nível 5
</section> <section class="utab__section" data-tab="Treinamento">
- Descrição do nível 1
- Descrição do nível 2
- Descrição do nível 3
- Descrição do nível 4
- Descrição do nível 5
</section> <section class="utab__section" data-tab="Ferreiro">
- Descrição do nível 1
- Descrição do nível 2
- Descrição do nível 3
- Descrição do nível 4
- Descrição do nível 5
</section> <section class="utab__section" data-tab="Cozinha">
- Descrição do nível 1
- Descrição do nível 2
- Descrição do nível 3
- Descrição do nível 4
- Descrição do nível 5
</section>
<script>
function handleArrowNavigation(event, buttons, activate) {
const keys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"];
if (!keys.includes(event.key)) {
return;
}
event.preventDefault();
const currentIndex = buttons.findIndex((button) => button === document.activeElement);
if (currentIndex === -1) {
return;
}
let nextIndex = currentIndex;
if (event.key === "Home") {
nextIndex = 0;
} else if (event.key === "End") {
nextIndex = buttons.length - 1;
} else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
nextIndex = (currentIndex - 1 + buttons.length) % buttons.length;
} else if (event.key === "ArrowRight" || event.key === "ArrowDown") {
nextIndex = (currentIndex + 1) % buttons.length;
}
activate(nextIndex, true); }
function triggerFade(element) {
element.classList.remove("is-fading");
void element.offsetWidth;
element.classList.add("is-fading");
}
function hasWikitext(value) {
return typeof value === "string" && (value.includes("[[") || value.includes("{{"));
}
function parseWikitextCached(raw, cacheKey, target) {
if (!raw || !hasWikitext(raw)) {
return Promise.resolve(raw);
}
if (target[cacheKey]) {
return Promise.resolve(target[cacheKey]);
}
if (!window.mw || !mw.Api) {
return Promise.resolve(raw);
}
const api = new mw.Api();
return api
.post({
action: "parse",
text: raw,
contentmodel: "wikitext",
prop: "text",
formatversion: 2
})
.then((response) => {
const html = response?.parse?.text || response?.parse?.text?.["*"] || raw;
target[cacheKey] = html;
return html;
})
.catch(() => raw);
}
const upgradeCosts = [
{ level: 1, berries: "50.000", gems: "10", points: "400" },
{ level: 2, berries: "250.000", gems: "10", points: "1.500" },
{ level: 3, berries: "400.000", gems: "20", points: "3.000" },
{ level: 4, berries: "1.000.000", gems: "50", points: "12.500" },
{ level: 5, berries: "1.800.000", gems: "90", points: "28.000" }
];
function buildLevelUI(section, tabLabel) {
const levelElements = Array.from(section.querySelectorAll(".utab__level"));
const levels = levelElements.map((levelElement, index) => {
const levelNumber = levelElement.dataset.level || String(index + 1);
const contentElement = levelElement.querySelector(".utab__content") || levelElement;
const rawHtml = contentElement.innerHTML.trim();
const contentWrapper = document.createElement("div");
contentWrapper.innerHTML = rawHtml;
const mediaImage = contentWrapper.querySelector(".utab__mediaImage");
const imageHtml = mediaImage ? mediaImage.innerHTML.trim() : "";
if (mediaImage) {
mediaImage.remove();
}
const statsHtml = contentWrapper.innerHTML.trim();
return {
level: levelNumber,
imageHtml,
statsHtml
};
});
levelElements.forEach((levelElement) => {
levelElement.classList.add("utab__level--source");
});
const nav = document.createElement("div");
nav.className = "utab__levels";
nav.setAttribute("role", "tablist");
nav.setAttribute("aria-label", `Níveis de ${tabLabel}`);
const display = document.createElement("div");
display.className = "utab__display";
const imageWrap = document.createElement("div");
imageWrap.className = "utab__image";
const stats = document.createElement("div");
stats.className = "utab__stats";
display.appendChild(imageWrap);
display.appendChild(stats);
const buttons = levels.map((level, index) => {
const button = document.createElement("button");
button.type = "button";
button.className = "utab__levelBtn";
button.textContent = `Nv ${level.level}`;
button.setAttribute("role", "tab");
button.setAttribute("aria-selected", "false");
button.setAttribute("tabindex", "-1");
button.addEventListener("click", () => activateLevel(index, true));
button.addEventListener("keydown", (event) => handleArrowNavigation(event, buttons, activateLevel));
nav.appendChild(button);
return button;
});
section.prepend(display);
section.prepend(nav);
let renderToken = 0;
function activateLevel(index, shouldFocus) {
if (!levels.length) {
return;
}
const safeIndex = Math.max(0, Math.min(index, levels.length - 1));
const current = levels[safeIndex];
const token = ++renderToken;
buttons.forEach((button, buttonIndex) => {
const isActive = buttonIndex === safeIndex;
button.classList.toggle("is-active", isActive);
button.setAttribute("aria-selected", isActive ? "true" : "false");
button.setAttribute("tabindex", isActive ? "0" : "-1");
});
if (current.imageHtml) {
imageWrap.innerHTML = current.imageHtml;
imageWrap.classList.remove("is-empty");
display.classList.remove("is-image-empty");
} else {
imageWrap.innerHTML = "";
imageWrap.classList.add("is-empty");
display.classList.add("is-image-empty");
}
const levelNumber = Number(current.level);
const cost = upgradeCosts.find((item) => item.level === levelNumber);
const costHtml = cost
? `
Custo do upgrade
- ${cost.berries} berries ${cost.gems ? `
- ${cost.gems} gemas ` : ""}
- ${cost.points} pontos
`
: "";
stats.innerHTML = `${current.statsHtml}${costHtml}`;
triggerFade(display);
const shouldParse =
(current.imageHtml && hasWikitext(current.imageHtml)) ||
(current.statsHtml && hasWikitext(current.statsHtml));
if (shouldParse) {
Promise.all([
parseWikitextCached(current.imageHtml, "parsedImageHtml", current),
parseWikitextCached(current.statsHtml, "parsedStatsHtml", current)
]).then(([parsedImage, parsedStats]) => {
if (renderToken !== token) {
return;
}
if (parsedImage && parsedImage !== current.imageHtml) {
imageWrap.innerHTML = parsedImage;
imageWrap.classList.remove("is-empty");
display.classList.remove("is-image-empty");
}
if (parsedStats && parsedStats !== current.statsHtml) {
stats.innerHTML = `${parsedStats}${costHtml}`;
}
});
}
if (shouldFocus) {
buttons[safeIndex].focus();
}
}
return {
activateLevel
};
}
function initTabber(widget) {
const sections = Array.from(widget.querySelectorAll(".utab__section"));
if (!sections.length) {
return;
}
const tabs = document.createElement("div");
tabs.className = "utab__tabs";
tabs.setAttribute("role", "tablist");
tabs.setAttribute("aria-label", "Categorias");
const tabButtons = [];
const sectionStates = [];
sections.forEach((section, index) => {
const label = section.dataset.tab || `Categoria ${index + 1}`;
section.classList.add("utab__panel");
section.setAttribute("role", "tabpanel");
section.setAttribute("aria-label", label);
const button = document.createElement("button");
button.type = "button";
button.className = "utab__tab";
button.textContent = label;
button.setAttribute("role", "tab");
button.setAttribute("aria-selected", "false");
button.setAttribute("tabindex", "-1");
button.addEventListener("click", () => activateTab(index, true));
button.addEventListener("keydown", (event) => handleArrowNavigation(event, tabButtons, activateTab));
tabs.appendChild(button);
tabButtons.push(button);
sectionStates.push(buildLevelUI(section, label));
});
widget.prepend(tabs);
function activateTab(index, shouldFocus) {
const safeIndex = Math.max(0, Math.min(index, sections.length - 1));
sections.forEach((section, sectionIndex) => {
const isActive = sectionIndex === safeIndex;
section.classList.toggle("is-active", isActive);
section.setAttribute("aria-hidden", isActive ? "false" : "true");
const tabButton = tabButtons[sectionIndex];
tabButton.classList.toggle("is-active", isActive);
tabButton.setAttribute("aria-selected", isActive ? "true" : "false");
tabButton.setAttribute("tabindex", isActive ? "0" : "-1");
});
sectionStates[safeIndex]?.activateLevel(0, false);
if (shouldFocus) {
tabButtons[safeIndex].focus();
}
}
activateTab(0, false); }
function initTabbers() {
document.querySelectorAll(".utab").forEach(initTabber);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initTabbers);
} else {
initTabbers();
}
</script>