O Camilo Micheletto recentemente entregou umas alterações bem legais no Computaria. Pedi pra ele ajuda pra colocar o dark-theme, aí ele aproveitou e colocou uma animção nos links de navegação!

Sério, olha que legal, bota o mouse em cima:

<div class="stampede-container local-stampede">
    <p>HOVER AQUI</p>
</div>

HOVER AQUI

Ok, isso exemplifica a animação. Mas, qual foi o problema?

Bem, a animação ia da direita para a esquerda. O bunny stampede tinha uma direção. Porém, eu queria que o lance fosse:

  • previous: coelhos indo para a esquerda (indo pra “trás”)
  • next: coelhos indo para a direita (indo pra “frente”)

Ou seja: a direção do movimento dos coelhos igual à direção que a seta aponta.

E eu também não queria fazer uma nova imagem! Ou seja, eu queria uma solução em que a direção da imagem fosse alterada usando apenas CSS.

A solução para isso é fácil, né? Só colocar um transform: scaleX(-1)? Vamos tentar, vou adicionar isso no estilo do componente acima:

<div class="stampede-container local-stampede" style="transform: scaleX(-1);">
    <p>HOVER AQUI</p>
</div>

HOVER AQUI

Então… ele virou tudo, né? Não só o stampede dos coelhos… então, como que resolvemos isso? Adicionando um novo componente HTML!

Esse novo componente precisa de algumas características:

  • precisa ocupar a altura e o comprimento do pai
  • não pode interferir no posicionamenot dos irmãos

Em tese tanto faz a tag, escolhi fazer com <span>. Para ficar com a mesma altura e comprimento do pai, coloquei heigth: 100%; width: 100%;. Mas isso ainda luta com a questão de posicionamento dos irmãos…

Procurando um pouco, encontrei essa referência aqui: How to create same height div as parent height. E notei que para fazer o que ele precisava de cobrir todo o elemento pai ele usou position: absolute;, e colocou o pai com position: relative;. Então, será que agora dá certo? Primeiramente, vamos testar com o stampede apenas na <span>, sem dar o scaleX nos coelhos…

<div class="stampede-container">
    <p>HOVER AQUI</p>
    <span class="stampede"></span>
</div>

HOVER AQUI

Hmmm, ele não tá localizando a questão do height nem do width corretamente. E se eu mandar ele se posicionar de modo absoluto?

<div class="stampede-container">
    <p>HOVER AQUI</p>
    <span class="stampede" style="position: absolute;"></span>
</div>

HOVER AQUI

Muito bem. Agora ele detecta o hover. Porém tá ainda… um tanto quanto off. Vou resetar a posição dele, pra ver no que que dá:

<div class="stampede-container">
    <p>HOVER AQUI</p>
    <span class="stampede" style="position: absolute; top: 0px;"></span>
</div>

HOVER AQUI

Ok, agora parece bom. Vamos adicionar o scaleX para ver se apenas a direção do stampede é alterada:

<div class="stampede-container">
    <p>HOVER AQUI</p>
    <span class="stampede" style="position: absolute; top: 0px; transform: scaleX(-1);"></span>
</div>

HOVER AQUI

Resolvido! Só para evitar colocar classes soltas, vamos agregar as coisas no lugar correto? Em uma classe fechadinha?

Bem, fica assim:

<div class="stampede-container">
    <p>HOVER AQUI</p>
    <span class="stampede stampede-position-fix"></span>
</div>

HOVER AQUI

As classes CSS usadas foram essas:

.stampede-container {
    position: relative;
    min-height: 32px;
}

.stampede-container.local-stampede:hover {
    background-image: url("{{ site.baseurl }}/assets/coelho-pattern.png");

    background-repeat: repeat;
    animation: infinite-scroll 4s linear infinite;
}

.stampede-container:hover .stampede {
    background-image: url("{{ site.baseurl }}/assets/coelho-pattern.png");

    background-repeat: repeat;
    animation: infinite-scroll 4s linear infinite;
}

.stampede {
    width: 100%;
    height: 100%;
}

.stampede-position-fix {
    position: absolute;
    top: 0px;
    left: 0px;
    z-index: -1;
}

Cadastro de bloco Liquid

Bem, eu estava me repetindo demais colocando o código de exibição e ao mesmo tempo repetindo-o como bloco de código para ficar visível ao leitor. Por exemplo:

```html
<div class="stampede-container">
    <p>HOVER AQUI</p>
    <span class="stampede stampede-position-fix"></span>
</div>
```
<div class="stampede-container">
    <p>HOVER AQUI</p>
    <span class="stampede stampede-position-fix"></span>
</div>

Então, para evitar ficar fazendo essa reescrita constante, resolvi que deveria emitir tanto verbatim como também como bloco de código. Para tal, fiz o seguinte construto:

{% verbatim_etc html %}
<div class="stampede-container">
    <p>HOVER AQUI</p>
    <span class="stampede stampede-position-fix"></span>
</div>
{% endverbatim_etc %}

Que automaticamente deveria gerar as duas coisas. Mas, como fazer?

Usei como base o código para o bloco highlight e também uma dica que vi nessa resposta.

Assim, registrei meu bloco:

Liquid::Template.register_tag("verbatim_etc", Computaria::VerbatimEtc)

E agora preciso implementar o VerbatimEtc. Tal qual em Usando as tags - Parte 1: página de tags, o jeito de fazer isso é usando o sistema de plugins de Jekyll. Agora para blocos, descrito em tags.

Finalmente, a magia para renderizar foi apenas pedir uma instância do renderizador de markdown e de renderizador de Liquid:

class VerbatimEtc < Liquid::Block
    def initialize(tag_name, markup, tokens)
        super
    end

    # https://talk.jekyllrb.com/t/markdown-parsing-order-in-custom-liquid-tags/4397/3
    def render(context)
        code = super.to_s.strip

        site = context.registers[:site]
        converter = site.find_converter_instance(::Jekyll::Converters::Markdown)



        rendered = Liquid::Template.parse(converter.convert("""

\`\`\`
#{code}
\`\`\`


#{code}
        """)).render(context)

        rendered
    end
end

No primeiro momento não estranhei a questão de que não tem tinha uma linguagem informada. Fui atrás de descobrir como que se informaria uma linguagem e eu descobri que ela vem no segundo parâmetro do construtor, denominado markup. Então, bastou guardar ele em uma variável de objeto e invocar quando for renderizar o bloco de código:

class VerbatimEtc < Liquid::Block
    def initialize(tag_name, markup, tokens)
        super

        @lang = markup.strip
    end

    # https://talk.jekyllrb.com/t/markdown-parsing-order-in-custom-liquid-tags/4397/3
    def render(context)
        code = super.to_s.strip

        site = context.registers[:site]
        converter = site.find_converter_instance(::Jekyll::Converters::Markdown)



        rendered = Liquid::Template.parse(converter.convert("""

\`\`\`#{@lang}
#{code}
\`\`\`


#{code}
        """)).render(context)

        rendered
    end
end

O método strip da string remove as “pontas” dela. Necessário no @lang = markup.strip.

E com isso consegui fornecer tanto uma rápida visualização para o conteúdo sem grandes possibilidades de eu cometer falhas em replicar para ter algo visível para o artigo, mantendo tanto o código quanto o efeito desejado na visualização.