Vídeo para um produto

Neste artigo vamos adicionar um vídeo para o detalhe do produto, mostrado no final da galeria de imagens:

Esta funcionalidade, assim como o vídeo na página inicial, permite a exibição de vídeos do Youtube e do Vimeo. Se você já o implementou em sua loja para a home, notará algumas pequenas diferenças que recomendamos que faça.

HTML

1. Dentro da pasta snipplets, crie um novo arquivo chamado video-item.tpl, que usaremos para o vídeo e sua miniatura. Este componente usa lazy load. Se você não o tiver em seu site, recomendamos este artigo.

{% if product_modal %}

    {# Product video modal wrapper #}

    <div id="product-video-modal" class="js-product-video-modal product-video" style="display: none;">
{% endif %}
        <div class="js-video {% if product_video %}js-video-product{% endif %} embed-responsive embed-responsive-16by9 visible-when-content-ready">

            {% if product_modal_trigger %}

                {# Open modal in mobile with product video inside #}

                <a href="#product-video-modal" data-fancybox="product-gallery" class="js-play-button video-player d-block d-md-none">
                    <div class="video-player-icon">{% include "snipplets/svg/play-circle.tpl" with {svg_custom_class: "icon-inline svg-icon-invert"} %}</div>
                </a>
            {% endif %}
            <a href="#" class="js-play-button video-player {% if product_modal_trigger %}d-none d-md-block{% endif %}">
                <div class="video-player-icon">
                    {% include "snipplets/svg/play-circle.tpl" with {svg_custom_class: "icon-inline svg-icon-invert"} %}
                </div>
            </a>
            <div class="js-video-image">
                <img src="{{ 'images/empty-placeholder.png' | static_url }}" data-src="" class="lazyload video-image fade-in" alt="{{ 'Video de' | translate }} {% if template != 'product' %}{{ product.name }}{% else %}{{ store.name }}{% endif %}" style="display: none;">
                <div class="placeholder-fade">
                </div>
            </div>
        </div>
            
        {# Empty iframe component: will be filled with JS on play button click #}


        <div class="js-video-iframe embed-responsive embed-responsive-16by9" style="display: none;" data-video-color="{{ settings.primary_color | trim('#') }}">
        </div>
{% if product_modal %}
    </div>
{% endif %}

2. Em seguida, criamos outro arquivo com o nome product-video.tpl dentro da pasta snipplets/product, que usaremos para incluí-lo nos detalhes do produto. Desta forma, o vídeo será mostrado na última das imagens.

{% if product.video_url %}
    {% if product.images_count > 1 %}
        {% set video_index = product.images_count %}
    {% else %}
        {% set video_index = 1 %}
    {% endif %}
    <div class="js-product-slide js-product-video-slide swiper-slide slider-slide" data-image-position="{{ video_index }}">
        <div class="product-video-container">
            <div class="product-video">
                {# Visible video inside slider #}
                {% include 'snipplets/video-item.tpl' with {product_modal_trigger: true, product_video: true} %}

                {# Hidden video inside modal #}
                {% include 'snipplets/video-item.tpl' with {product_modal: true, product_video: true} %}
            </div>
        </div>
    </div>
{% endif %}

3. Depois que esses dois arquivos forem criados, iremos para o arquivo product-image.tpl e apenas onde termina o "for" que itera sobre as imagens do produto, adicionamos a chamada para product-video.tpl. Deve ser parecido com o seguinte:

{% set has_multiple_slides = product.images_count > 1 or product.video_url %}

{% if product.images_count > 0 %}
    <div class="js-swiper-product nube-slider-product swiper-container" style="visibility:hidden; height:0;">
        {% include 'snipplets/labels.tpl' with {'product_detail': true} %}
        <div class="swiper-wrapper">
            {% for image in product.images %}
             <div class="swiper-slide js-product-slide slider-slide" data-image="{{image.id}}" data-image-position="{{loop.index0}}">
                 <a href="{{ image | product_image_url('huge') }}" data-fancybox="product-gallery" class="d-block p-relative" style="padding-bottom: {{ image.dimensions['height'] / image.dimensions['width'] * 100}}%;">
                     <img src="{{ 'images/empty-placeholder.png' | static_url }}" data-srcset='{{  image | product_image_url('large') }} 480w, {{  image | product_image_url('huge') }} 640w' data-sizes="auto" class="js-product-slide-img product-slider-image img-absolute img-absolute-centered lazyautosizes lazyload" {% if image.alt %}alt="{{image.alt}}"{% endif %}/>
                     <img src="{{ image | product_image_url('tiny') }}" class="js-product-slide-img product-slider-image img-absolute img-absolute-centered blur-up" {% if image.alt %}alt="{{image.alt}}"{% endif %} />
                </a>
             </div>
            {% endfor %}
            {% include 'snipplets/product/product-video.tpl' %}
        </div>
        <div class="js-swiper-product-pagination swiper-pagination swiper-pagination-white"></div>
        {% if has_multiple_slides %}
            <div class="js-swiper-product-prev swiper-button-prev d-none d-md-block">{% include "snipplets/svg/chevron-left.tpl" with {svg_custom_class: "icon-inline icon-w-8 icon-2x svg-icon-text"} %}</div>
            <div class="js-swiper-product-next swiper-button-next d-none d-md-block">{% include "snipplets/svg/chevron-right.tpl" with {svg_custom_class: "icon-inline icon-w-8 icon-2x svg-icon-text"} %}</div>
        {% endif %}
    </div>
    {% snipplet 'placeholders/product-detail-image-placeholder.tpl' %}
{% endif %}

Olhando o código de perto, notamosum condicional has_multiple_slides que é definido no início do arquivo e o usamos para mostrar as setas do slider quando há muitas imagens ou pelo menos uma imagem e um vídeo.

Por outro lado, é importante mencionar que o código utiliza classes de um slider feito com Swiper.

4. Vamos precisar adicionar uma classe no arquivo labels.tpl (ou onde quer que você tenha seus banners de venda, frete grátis, etc.) para conectar com o Javascript que irá esconder essas mensagens quando o vídeo estiver sendo visualizado.

No div que engloba todos os rótulos, vamos adicionar o condicional {% if product.video_url e product%} js-labels-group {% endif%}, deixando o seguinte:

{% if show_labels %}
  <div class="{% if product.video_url and product %}js-labels-group{% endif %} labels">
    {% if not product.has_stock %}
    ….
  </div>
{% endif %}

5. Adicione o arquivo SVG para o ícone de "play" do vídeo. Ele se chamará play-circle.tpl e o criaremos na pasta snipplets/svg com o seguinte código

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z"/></svg>

6. Esta parte é opcional, se você já implementou o vídeo na página inicial, agora pode usar o arquivo video-item.tpl para salvar o código. No arquivo home-video.tpl apenas substitua todo o código por este:

{% if settings.video_embed %}
    <section class="section-video-home" data-store="video-home">
        <div class="container{% if settings.video_full %}-fluid p-0{% endif %}">
            <div class="row no-gutters">
                <div class="col">
                    {% include 'snipplets/video-item.tpl' %}
                </div>
            </div>
        </div>
    </section>
{% endif %}

CSS

Requisito:

Ter adicionado helper classes em seu layout. Você pode seguir este pequeno tutorial para fazer isso (é só copiar e colar algumas classes, não leva mais que 1 minuto).

1. Adicionamos o seguinte SASS de cores em style-colors.scss.tpl (ou na stylesheet do seu layout que possui as cores e fontes da loja). Lembre-se de que as variáveis de cores e fontes podem variar em relação ao seu layout:

.product-video-container {
  background-color: rgba($main-foreground, .07);
}

.embed-responsive {
  background: $main-foreground;
}

2. Adicione os estilos no arquivo static/style-critical.tpl

Se em seu layout você usar um stylesheet para o CSS crítico, precisaremos do seguinte código dentro dele, do contrário, pode adicionar no seu CSS geral.

{# /* // Video */ #}

.embed-responsive {
  position: relative;
  display: block;
  height: 0;
  padding: 0;
  overflow: hidden;
}
.embed-responsive.embed-responsive-16by9 {
  padding-bottom: 56.25%;
}
.embed-responsive .embed-responsive-item,
.embed-responsive embed,
.embed-responsive  iframe,
.embed-responsive  object,
.embed-responsive  video {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.video-player {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  cursor: pointer;
}
.video-player-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 60px;
  height: 60px;
  margin: -30px 0 0 -30px;
  padding: 0;
  font-size: 60px;
  line-height: 30px;
  text-align: center;
  pointer-events: none;
}
.video-image {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  height: auto;
  transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
}

.product-video-container {
  display: block;
  width: 100%;
  height: 100%;
}
.product-video {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
}
.product-video .embed-responsive {
  width: 100%;
  height: 100%;
  padding-bottom: 0;
}
.product-video .video-image{
  width: auto;
  height: 100%;
}

{# /* // Min width 768px */ #}

@media (min-width: 768px) { 
    {# /* //// Product detail */ #}

    .product-video .video-image,
    .product-video .embed-responsive {
        width: 100%;
        height: auto;
    }

    .product-video .embed-responsive {
        padding-bottom: 56.25%;
    }
}

JS

⚠️ A partir do dia 30 de janeiro de 2023, a biblioteca jQuery será removida do código de nossas lojas, portanto, a função "$" não poderá ser utilizada.

1. O JavaScript de que precisamos para adicioná-lo ao arquivo store.js.tpl (ou onde quer que você tenha suas funções JS). Adicionamos o seguinte código:

{% if template == 'product' and product.video_url %}
    {% set video_url = product.video_url %}
{% endif %}

{% if video_url %}

    {# /* // Youtube or Vimeo video for home or each product */ #}

    LS.loadVideo('{{ video_url }}');

{% endif %}

Caso você já tenha um vídeo na página inicial, simplesmente exclua o código que você tinha e, em vez do código que vemos acima, adicione o seguinte:

{% if template == 'home' %}
    {% set video_url = settings.video_embed %}
{% elseif template == 'product' and product.video_url %}
    {% set video_url = product.video_url %}
{% endif %}

{% if video_url %}

    {# /* // Youtube or Vimeo video for home or each product */ #}

    LS.loadVideo('{{ video_url }}');
    
{% endif %}

2.  Vamos adicionar condicionais dentro do slider para os detalhes do produto, localizado no arquivo store.js.tpl. Podemos encontrá-lo com a seguinte linha:

'.js-swiper-product',

A primeira coisa que vamos fazer é definir uma condição para entender quando há muitos slides:

{% set has_multiple_slides = product.images_count > 1 or video_url %}

Então, dentro do evento "init" onde sabemos que o slider já foi iniciado, adicionamos o código de forma que o slide de vídeo tenha a altura slider e fique  centralizado verticalmente. Deve ser parecido com isto

init: function () {
    jQueryNuvem(".js-product-slider-placeholder").hide();
    jQueryNuvem(".js-swiper-product").css("visibility", "visible").css("height", "auto");
    {% if video_url %}
        productSwiperHeight = jQueryNuvem(".js-swiper-product").height();
        jQueryNuvem(".js-product-video-slide").height(productSwiperHeight);
    {% endif %}
},

Abaixo adicionaremos um evento para quando o slide for alterado para que possamos ocultar ou mostrar os cartazes de venda, desconto e frete grátis quando o slide visível for um vídeo.

{% if video_url %}
    slideChangeTransitionEnd: function () {
        if(jQueryNuvem(".js-product-video-slide").hasClass("swiper-slide-active")){
            jQueryNuvem(".js-labels-group").fadeOut(100);
        }else{
            jQueryNuvem(".js-labels-group").fadeIn(100);
        }
        jQueryNuvem('.js-video').show();
        jQueryNuvem('.js-video-iframe').hide().find("iframe").remove();
    },
{% endif %}

Toda a função do controle deslizante deve ser semelhante a esta:

{% set has_multiple_slides = product.images_count > 1 or video_url %}

var productSwiper = null;
createSwiper(
    '.js-swiper-product',
    {
        lazy: true,
        loop: false,
        pagination: {
            el: '.js-swiper-product-pagination',
            type: 'fraction',
            clickable: true,
        },
        navigation: {
            nextEl: '.js-swiper-product-next',
            prevEl: '.js-swiper-product-prev',
        },
        on: {
            init: function () {
                jQueryNuvem(".js-product-slider-placeholder").hide();
                jQueryNuvem(".js-swiper-product").css("visibility", "visible").css("height", "auto");
                {% if video_url %}
                    productSwiperHeight = jQueryNuvem(".js-swiper-product").height();
                    jQueryNuvem(".js-product-video-slide").height(productSwiperHeight);
                {% endif %}
            },
            {% if video_url %}
                slideChangeTransitionEnd: function () {
                    if(jQueryNuvem(".js-product-video-slide").hasClass("swiper-slide-active")){
                        jQueryNuvem(".js-labels-group").fadeOut(100);
                    }else{
                        jQueryNuvem(".js-labels-group").fadeIn(100);
                    }
                    jQueryNuvem('.js-video').show();
                    jQueryNuvem('.js-video-iframe').hide().find("iframe").remove();
                },
            {% endif %}
        },
    },
    function(swiperInstance) {
        productSwiper = swiperInstance;
    }
);

Traduções

Nesta etapa, adicionamos os textos para as traduções no arquivo config/translations.txt

es "Video de"
pt "Vídeo de"
en "Video of"
es_mx "Video de"

Ativação

Você pode ativar a funcionalidade na forma de qualquer produto, basta ir até a parte que diz "Vídeo" e colar seu link do Youtube ou Vimeo.