Skip to content

Extend template for a custom block

Yvain Liechti edited this page Jul 25, 2016 · 2 revisions

You can add your customized handlebars helper with --extend option (or "extend": in your json config file), whose value is the path towards the directory where extension files are.

List icons of a font-icon by example

We want to document the content of a font-icon: character, name and description of each icon.

// Icons font
//
// Icons:
// left    : ← - arrow to left
// up      : ↑ - arrow to top
// right   : → - arrow to right
// down    : ↓ - arrow to bottom
// comment : 💬 - bulle
//
// Styleguide Icons

And add Icons as customized block putting the --custom option in the command line or in the json config file:

  "custom": [
    "Icons"
  ]

You need to define some style in your scss of the kss assets:

  .kss-icons {
    padding: 0;
    margin: 0;
    list-style: none;

    > li {
      overflow: hidden;
    }
  }
  .kss-icons__demo {
    float: left;
    box-sizing: content-box;
    height: 40px;
    padding: 30px 0;
    width: 100px;
    text-align: center;
    border: 2px solid $kss-colors-quotes;
    font-size: 40px;
    margin-bottom: .25em;

    // lib/icon
    font-family: $font-icon;
    speak: none;
    font-style: normal;
    font-weight: normal;
    font-variant: normal;
    text-transform: none;
    line-height: 1;

    // Better Font Rendering
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
  .kss-icons__info {
    margin-left: 120px;

    p {
      margin-top: 0;
    }
  }
  .kss-icons__name {
    font-weight: bold;
  }
  .kss-icons__char {
    margin: 0;
  }
  .kss-icons__description {
    color: $kss-colors-quotes;
  }

The Handlebars way

Handlebars helper file:

module.exports = function (Handlebars) {
  'use strict';

  Handlebars.registerHelper('kssIcons', function (doc, block) {
    var output = [];
    var regex = /^(\S+)\s*:\s*(\S+)(?:\s*-\s*(.*))?$/gm;
    var test;

    while ((test = regex.exec(doc)) !== null) {
      this.icon = {};
      this.icon.name = test[1];
      this.icon.character = test[2];
      if (test[3] !== undefined) {
        this.icon.description = test[3];
      }

      output.push(block.fn(this));
    }

    return output.join('');
  });
};

Use it in your kss template (index.hbs in builder):

{{#if icons}}
  <ul class="kss-icons">
    {{#kssIcons icons}}
      <li>
        <div class="kss-icons__demo">{{icon.character}}</div>
        <div class="kss-icons__info">
          <p><strong class="kss-icons__name">{{icon.name}}</strong>: <code class="kss-icons__char">{{icon.character}}</code></p>
          <p class="kss-icons__description">{{{icon.desc}}}</p>
        </div>
      </li>
    {{/kssIcons}}
  </ul>
{{/if}}

The twig way

Twig extension file:

module.exports = function (Twig) {
  'use strict';

  Twig.extend(function (Twig) {

    // example of extending a tag type that would
    // restrict content to the specified "level"
    Twig.exports.extendTag({
      // unique name for tag type
      type: 'kssIcons',
      // regex for matching tag
      regex: /^kssIcons\s+(.+)$/,

      // what type of tags can follow this one.
      next: ['endkssIcons'], // match the type of the end tag
      open: true,
      compile: function (token) {
        var expression = token.match[1];

        // turn the string expression into tokens.
        token.stack = Twig.expression.compile.apply(this, [{
          type:  Twig.expression.type.expression,
          value: expression
        }]).stack;

        delete token.match; // cleanup
        return token;
      },
      parse: function (token, context, chain) {
        var doc = Twig.expression.parse.apply(this, [token.stack, context]);
        var output = [];
        var regex = /^(\S+)\s*:\s*(\S+)(?:\s*-\s*(.*))?$/gm;
        var test;

        while ((test = regex.exec(doc)) !== null) {
          var innerContext = Twig.ChildContext(context);
          innerContext.icon = {};
          innerContext.icon.name = test[1];
          innerContext.icon.character = test[2];
          if (test[3] !== undefined) {
            innerContext.icon.description = test[3];
          }

          output.push(Twig.parse.apply(this, [token.output, innerContext]));

          Twig.merge(context, innerContext, true);
        }

        return {
          chain: chain,
          output: Twig.output.apply(this, [output])
        };
      }
    });

    // a matching end tag type
    Twig.exports.extendTag({
        type: 'endkssIcons',
        regex: /^endkssIcons$/,
        next: [ ],
        open: false
    });
  });
};

Use it in your kss template (index.twig in builder):

{% if section.icons %}
  <ul class="kss-icons">
    {% kssIcons section.icons %}
      <li>
        <div class="kss-icons__demo">{{ icon.character }}</div>
        <div class="kss-icons__info">
          <p><strong class="kss-icons__name">{{ icon.name }}</strong>: <code class="kss-icons__char">{{ icon.character }}</code></p>
          <p class="kss-icons__description">{{ icon.desc|raw }}</p>
        </div>
      </li>
    {% endkssIcons %}
  </ul>
{% endif %}

Customize it according to the style you wish.

Edit hbs, twig and scss file to customize it as you want.