Narrative Change Collection view to grid on Mobile

Solved
Highlighted
Tourist
4 0 1

Hi,

I am using Narrative theme and I have a problem with the featured-collection section. I want to have grid layouts for BOTH desktop and mobile. I looked into the javascript and realize grid style seems to work only for desktop view.

Here are how they look like: you can see rows are not aligned only in mobile view.

desktopdesktopmobilemobile

In desktop version, the product cards are given a fixed height with javascript. But for mobile, no height is given to it.

I tried to change the javascript but to no avail. I couldn't find which line exactly put the css height on the product card.

 

Could anyone shed some light on this? Thank you.

0 Likes
Highlighted
Tourist
4 0 1

 

This is the whole card manager script. I could't find which exact line gives css height to product card(cardWrapper) .

There are a couple of !utils.isMobile() in here, I have tried to take them out and still not working.

 

 

/*

Card Manager Extension
--------------------------------------------------------------------------------
Manages the drawer functionilty of the cart drawer section


Events
------------

Name: cards_load_start
Description: Fired before cards start to load
Payload: none

Name: card_loaded
Description: Fired each time a card is loaded onto the page
Payload: { object } Card DOM element

Name: cards_load_done
Description: Fired when all cards have loaded
Payload: none

*/

var classes$6 = {
  cardListSubLoaded: 'card-list__sub-actions--loaded',
  cardReveal: 'card--reveal',
  searchTemplate: 'template-search'
};

var selectors$6 = {
  cardList: '.card-list',
  cardListColumn: '.card-list__column',
  cardListSub: '.card-list__sub-actions',
  card: '.card',
  cardWrapper: '.card__wrapper',
  cardInfo: '.card__info'
};

var cardManager = {
  init: function() {
    this.$cardList = $(selectors$6.cardList, this.$container);
    this.$emptyColumn = $(selectors$6.cardListColumn, this.$container)
      .clone()
      .empty();
    this.$cards = $(selectors$6.card, this.$container);

    this.desktopColumnCount = this.$cardList.data('desktop-columns') || 2;
    this.mobileColumnCount = this.$cardList.data('mobile-columns') || 2;
    this.limitCount = this.$cardList.data('limit') || 10;
    this.columnCount = utils.isMobile()
      ? this.mobileColumnCount
      : this.desktopColumnCount;
    this.gridStyle = this.$cardList.data('grid-style') || 'grid';
    this.windowWidth = $(window).outerWidth();
    this.cardLoadPromises = [];
    
    this.window().on('resize', this._onResize.bind(this));

    this.on('keydown', selectors$6.cardWrapper, this._onCardTabDown.bind(this));
    this.on('keyup', this._onCardTabUp.bind(this));
    
    utils.promiseStylesheet().then(
      function() {
        this.cardsLoaded = this._loadCards();

        $('html').removeClass('site-footer--hidden');

        $(selectors$6.cardListSub, this.$container)
          .prepareTransition()
          .addClass(classes$6.cardListSubLoaded);
      }.bind(this)
    );
    
//Restrict mobile row numbers-part1
if (utils.isMobile()) {
    var a;
    for (a = 4; a < this.limitCount; a++) {
    this.$cards.eq(a).addClass('mobilehiderow');
    }};
    
  },
          
  _onResize: function() {
    var columnCount = utils.isMobile()
      ? this.mobileColumnCount
      : this.desktopColumnCount;
    
    // Only replace columns if the number of columns changes.
    if (this.columnCount !== columnCount) {
      this.columnCount = columnCount;
      this.$columns = this._replaceColumns();
    }

    $.each(
      this.$cards,
      function(index) {
        if (utils.isMobile()) {
          this.$columns.find(selectors$6.cardWrapper).removeAttr('style');
          
//Restrict mobile row numbers-part2
          if(index > 3) {
            this.$cards.eq(index).addClass('mobilehiderow');
          }
                    
        } else if (this._isAlignedRow(index + 1)) {
//Remove row restriction         
          this.$cards.removeClass('mobilehiderow');
          
          var rowNumber =
            (index - (index % this.desktopColumnCount)) /
              this.desktopColumnCount +
            1;
          this._matchRowHeights(this.$columns, rowNumber);
        
        }
      }.bind(this)
    );
  },

  _onCardTabDown: function(evt) {
    if (evt.keyCode !== 9) return; // Only continue if tab key is pressed

    var index = $(evt.target).data('tabindex');

    this.tabFromList = true;

    if (evt.shiftKey) {
      if (index > 1) {
        evt.preventDefault();
        $('[data-tabindex=' + (index - 1) + ']').focus();
      }
    } else {
      if (index === this.$cards.length) {
        $(selectors$6.cardWrapper, this.$container)
          .last()
          .focus();
      } else {
        evt.preventDefault();
        $('[data-tabindex=' + (index + 1) + ']').focus();
      }
    }
  },

  _onCardTabUp: function(evt) {
    if (evt.keyCode !== 9) return;

    var tabFromList = this.tabFromList || false;
    this.tabFromList = false;

    if (!evt.shiftKey || tabFromList) return;

    if (
      $(selectors$6.cardWrapper, this.$container)
        .last()
        .is(evt.target)
    ) {
      $('[data-tabindex=' + this.$cards.length + ']').focus();
    }
  },

  _loadCards: function() {
    this.trigger('cards_load_start');

    this.$columns = this._addColumns();

    return this._promiseAllCardsReveal().always(
      function() {
        this.trigger('cards_load_done');
      }.bind(this)
    );
  },

  _addColumns: function() {
    var $columns;
    for (var i = 1; i < this.columnCount; i++) {
      this.$cardList.append(this.$emptyColumn.clone());
    }

    $columns = $(selectors$6.cardListColumn, this.$container);
    $columns.heights = fill(Array(this.columnCount), 0);
    $columns.lengths = fill(Array(this.columnCount), 0);

    return $columns;
  },

  _replaceColumns: function() {
    var $columns = this.$emptyColumn.clone();

    $columns.heights = fill(Array(this.columnCount), 0);
    $columns.lengths = fill(Array(this.columnCount), 0);

    for (var i = 1; i < this.columnCount; i++) {
      $columns.push(this.$emptyColumn.clone()[0]);
    }

    $.each(
      this.$cards,
      function(index, card) {
        this._positionCard($(card), index, $columns);
      }.bind(this)
    );

    this.$cardList.html($columns);

    return $columns;
  },

  _promiseAllCardsReveal: function() {
    var series = $.Deferred().resolve();

    this.$cards.each(
      function(index, card) {
        // Position the card in one of the available columns
        this._positionCard($(card), index, this.$columns);

        // Check that we have an aligned row and isMobile is false
        if ( !utils.isMobile() && this._isAlignedRow(index + 1)) {
          var rowNumber = this.$columns.lengths[0];
          this._matchRowHeights(this.$columns, rowNumber);
        }

        // We want to check immediately if the card should be revealed, not after
        // a previous `.then()` in our series has been fulfilled.
        var promiseRevealReady = this._promiseRevealReady(card);

        // Add the following steps to our series of promises for each card:
        // 1. Promise the card is ready to be revealed
        // 2. Reveal the card
        // 3. Delay 80ms
        series = series
          .then(function() {
            return promiseRevealReady;
          })
          .then(this._revealCard.bind(this, card))
          .then(function() {
            return $.Deferred(function(defer) {
              setTimeout(defer.resolve, 80);
            });
          });
      }.bind(this)
    );
    return series;
  },

  _revealCard: function(card) {
    var $card = $(card);

    this.trigger('card_loaded', [$card[0]]);

    requestAnimationFrame($card.addClass.bind($card, classes$6.cardReveal));
  },

  // A promise that will be fulfilled when a card is ready to be revealed
  _promiseRevealReady: function(card) {
    return $.Deferred(function(defer) {
      var $card = $(card);

      if (!($('html').hasClass('is-ios') && Shopify.designMode)) {
        // If we already triggered the animation, then resolve the promise to show
        // the card. Wrap the position check in requestAnimationFrame to make sure
        // that the browser is done positioning the element before it reads its
        // position.
        requestAnimationFrame(function() {
          if (utils.isInOrAboveViewport(card)) {
            return defer.resolve();
          }
        });

        // If we haven't triggered the animation, then wait for the animation
        // event for this card and then resolve the promise to show the card.
        $card.on('animate_element', onAnimate);

        function onAnimate(evt, element) {
          if (element !== card) return;

          $card.off('animate_element', onAnimate);
          defer.resolve();
        }
      } else {
        $(card).addClass(classes$6.cardReveal);
        defer.resolve();
      }
    });
  },

  _positionCard: function($card, index, $columns) {
    var columnIndex = 0;
    var cardHeight = $card.outerHeight(true);

    
    
    if (this.gridStyle === 'collage') {
      columnIndex = $columns.heights.indexOf(
        Math.min.apply(Math, $columns.heights)
      ); // Default to shortest column
      var threshold = 150;
      for (var i = 0; i < $columns.heights.length; i++) {
        if ($columns.heights[columnIndex] > $columns.heights[i] - threshold) {
          columnIndex = i;
          break;
        }
      }
    } else {
      columnIndex = $columns.lengths.indexOf(
        Math.min.apply(Math, $columns.lengths)
      );
    }

    $columns.eq(columnIndex).append($card);

    // Restore the height if it is 0 (needed for matching heights in the
    // 'aligned' grid)
    if ($card.outerHeight() === 0 && !utils.isMobile()) {
      $card.find(selectors$6.cardWrapper).outerHeight(cardHeight);
    }

    if (this.gridStyle === 'collage') {
      $columns.heights[columnIndex] += cardHeight;
    }
    $columns.lengths[columnIndex]++;

    $card.find('a').attr('data-tabindex', index + 1);
  },

  _matchRowHeights: function($columns, rowNumber) {
    var maxHeight = 0;
    var currentCardHeight = 0;
    var rowSelector = '';
    var isArticle = false;

    // Construct the selector for the cards in the current row
    for (var i = 0; i < $columns.length; i++) {
      rowSelector +=
        "[data-tabindex='" + ((rowNumber - 1) * $columns.length + i + 1) + "']";
      if (i < $columns.length - 1) {
        rowSelector += ', ';
      }
    }
    var $row = $columns.find(rowSelector).parent();

    for (var j = 0; j < $row.length; j++) {
      isArticle = $($row[j])
        .find(selectors$6.cardWrapper)
        .is('.card--article');

      currentCardHeight = $($row[j])
        .find(selectors$6.cardWrapper)
        .outerWidth();
      if ($(document.body).hasClass(classes$6.searchTemplate) && isArticle) {
        currentCardHeight = $($row[j])
          .find(selectors$6.cardWrapper)
          .outerHeight();
      } else {
        
        if(utils.isTablet()){
        currentCardHeight =
          $($row[j])
            .find(selectors$6.cardWrapper)
            .outerWidth() + 20 +
          $($row[j])
            .find(selectors$6.cardInfo)
            .outerHeight();
        }
          else {
                   currentCardHeight =
          $($row[j])
            .find(selectors$6.cardWrapper)
            .outerWidth() + 
          $($row[j])
            .find(selectors$6.cardInfo)
            .outerHeight(); 
          }
      }

      if (currentCardHeight> maxHeight) {
        maxHeight = currentCardHeight;
      }
    }


    $row.find(selectors$6.cardWrapper).outerHeight(maxHeight+20);
  },

  _isAlignedRow: function(index) {
    // Check if the gridStyle is 'grid', and if we are at the end of a row or
    // at the last card
    return (
      this.gridStyle === 'grid' &&
      (index % this.desktopColumnCount === 0 || index === this.$cards.length)
    );
  }
};

 

 

0 Likes
Highlighted
Shopify Partner
1544 332 446

Hey @rgdfz 

I read your description. Can you please provide your webshop URL?

I will check and provide you solution here.

Thanks!

If helpful then please Like and Accept Solution.
Do you need custom changes on store ? Hire me.
Feel free to Contact me on dmw.webartisan@gmail.com
Follow us on Instagram @dmw.webartisan
0 Likes
Highlighted
Shopify Partner
1544 332 446

This is an accepted solution.

Hey @rgdfz 

add code assets/theme.scss.liquid bottom of the file

@media only screen and (max-width:749px) {
.card__name-v1 {max-width: 100px; height: 85px;}
}

Hope this will work for you.


Thanks!

If helpful then please Like and Accept Solution.
Do you need custom changes on store ? Hire me.
Feel free to Contact me on dmw.webartisan@gmail.com
Follow us on Instagram @dmw.webartisan
1 Like
Highlighted
Tourist
4 0 1

Wow, this small hack works like a charm.

Thank you so much. @dmwwebartisan 

1 Like