Блоки стартового репозитория

Страница

Стили страницы (тег html имеет класс page), глобальные стили, типографика.

В стилизацию блока включена стилизация «прибитого подвала».

<!DOCTYPE html><html class="no-js  page" lang="ru"><head>...</head><body>  <div class="page__inner">    <div class="page__content">Обёртка основного содержимого</div>    <div class="page__footer-wrapper">Обёртка прибитого подвала</div>  </div></body></html>

Примеси-генераторы модульной сетки

В сборку берётся ./src/scss/mixins/grid-mixins.scss с примесями-генераторами. Используйте семантические классы и применяйте к ним примеси.

Пример использования на codepen.io.

Необходимая структура:

  • Контейнер — общая обёртка, обеспечивающая ширину, боковые внутренние отступы (padding) и центровку (margin: auto). Может содержать любой контент.
  • Прямой родитель сетки — обёртка ячеек, обеспечивающая отрицательные боковые отступы (margin).
  • Ячейки любой ширины (по умолчанию 12 колонок, для изменения — переопредить переменную).
<section class="promo">  <div class="promo__inner">    <h2>Заголовок промо</h2>    <p>Произвольный контент до модульной сетки</p>    <div class="promo__grid">      <div class="promo__img"></div>      <div class="promo__text"></div>    </div>  </div></section> .promo {  &__inner {    @include container();  }  &__grid {    @include row();  }  &__img {    @include col();    @include col(md, 5);  }  &__text {    @include col();    @include col(md, 7);  }}

SVG-спрайт c gulp-svgstore

Из файлов sprite-svg/svg/ генерируется файл спрайта sprite-svg/img/sprite.svg.

Блок не имеет классов, упоминаемых в разметке. Чтобы взять его в сборку, упомяните sprite-svg в config.js#alwaysAddBlocks.

Для вставки на страницу используйте svg > use со ссылками на id символа:

              svg(width="32", height="32")
                use(xlink:href="img/sprite.svg#icon-boo")
            

При использовании блока в проекте в сборку берётся svg4everybody.

PNG-спрайт с spritesmith

Из файлов sprite-png/png/ генерируется файл спрайта sprite-png/img/sprite-ЧИСЛОВОЙ_ИНДЕКС.svg.

Блок не имеет классов, упоминаемых в разметке. Чтобы взять его в сборку, упомяните sprite-png в config.js#alwaysAddBlocks.

Стилевой файл блока генерируется автоматически и содержит примеси для использования спрайтов.

Пример использования для конкретного селектора:

              .selector {
                @include sprite($icon-left); // $icon-left — $ИМЯ-ФАЙЛА-КАРТИНКИ
              }
            

Закрыть

Иконка закрытия.

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (close)
                   
                  mixin close(label, mods)
                   
                    //- Принимает:
                    //-   label {string} - описание, значение атрибута aria-label
                    //-   mods {string}  - стилевые модификаторы
                    //- Вызов:
                          +close('Закрыть')
                          +close('Закрыть', 'sm')
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' close--' + modsList[i].trim();
                        }
                      }
                   
                    button.close(class=allMods, type='button', aria-label=label, title=label)&attributes(attributes)
                      span= label
                

Бургер

Анимированное превращение в крестик по добавлению модификатора.
JS блока берет переданный в data-атрибуте идентификатор и, по клику на бургере, добавляет переданный в data-атрибуте класс на элемент с этим модификатором.

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (burger)
                   
                  mixin burger(label, targetId, switchableClass)
                   
                    //- Принимает:
                    //-   label           {string} - описание, значение атрибута aria-label
                    //-   targetId        {string} - атрибут id целевого элемента (без символа #), на котором по клику будет меняться класс
                    //-   switchableClass {string} - класс, добавляемый/убираемый с целевого элемента
                    //- Вызов:
                          +burger('Показать пример кода', 'burger-code', 'blocks-library__code--shown')
                          +burger('Показать ничто')(data-some="SOME")
                   
                    -
                      label = label || 'Toggle block ' + targetId
                      if (typeof(targetId) !== 'undefined' && targetId !== '') attributes['data-target-id'] = targetId
                      if (typeof(switchableClass) !== 'undefined' && switchableClass !== '') attributes['data-target-class-toggle'] = switchableClass
                   
                    button.burger(aria-label=label)&attributes(attributes)
                      span= label
                

Сообщения

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (alert)
                   
                  mixin alert(title, mods)
                   
                    //- Принимает:
                    //-   title {string} - заголовок
                    //-   mods {string}  - стилевые модификаторы
                    //- Вызов:
                          +alert()
                            p Текст
                          +alert('Внимание', 'warning, some-mod-name')
                            p Предупреждение
                            +close('Закрыть', 'sm')(class='alert__close', aria-label='Закрыть')
                          +alert('Внимание', 'danger')
                            p Проблема
                            +close('Закрыть', 'sm')(class='alert__close', aria-label='Закрыть')
                          +alert('Внимание', 'success')
                            p Успех
                            +close('Закрыть', 'sm')(class='alert__close', aria-label='Закрыть')
                   
                    -
                      //- список модификаторов
                      var allMods = '';
                      if(typeof(mods) === 'string') {
                        var modsList = mods.split(',');
                   
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' alert--' + modsList[i].trim();
                        }
                      }
                   
                    .alert(class=allMods, role='alert')&attributes(attributes)
                      if (typeof(title) !== 'undefined' && title !== '')
                        h4.alert__header!= title
                      block
                

Мини-карточка товара

Карточка товара (миниатюра-ссылка на страницу товара).

Новинка!
Товар1

Товар1

Описание1

7 777 ₽

Товар2

Товар2

12 000 ₽

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (card)
                   
                  mixin card(data, mods)
                   
                    //- Принимает:
                    //- data {
                    //-   url:   {string},  - адрес для ссылки
                    //-   img:   {string},  - адрес картинки товара
                    //-   name:  {string},  - название
                    //-   descr: {string},  - описание
                    //-   price: {number},  - цена
                    //-   new:   {boolean}, - показать метку «новинка»
                    //- }
                    //- mods {string}       - модификаторы
                    //- Вызов:
                          +card({
                            url: 'good01',
                            img: 'img/demo-product.jpg',
                            name: 'Товар1',
                            descr: 'Описание1',
                            price: 7777,
                            new: true,
                          }, 'mod')
                          +card({
                            img: 'img/demo-product.jpg',
                            name: 'Товар2',
                            price: 12000,
                          })
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' card--' + modsList[i].trim();
                        }
                      }
                      var newLabel = (data.new !== 'undefined' && data.new) ? '<div class="card__new">Новинка!</div>' : '';
                      var price = '' + data.price;
                      var price = price.replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ') + ' ₽';
                   
                    article.card(class=allMods)&attributes(attributes)
                      != newLabel
                      if (data.url !== 'undefined' && data.url)
                        .card__inner
                          a.card__img-wrap(href=data.url)
                            img.card__img(src=data.img, alt=data.name)
                          h3.card__title
                            a(href=data.url)!= data.name
                          if (data.descr !== 'undefined' && data.descr)
                            p.card__descr!= data.descr
                          p.card__price!= price
                      else
                        .card__inner
                          span.card__img-wrap
                            img.card__img(src=data.img, alt=data.name)
                          h3.card__title!= data.name
                          if (data.descr !== 'undefined' && data.descr)
                            p.card__descr!= data.descr
                          p.card__price!= price
                   
                      +btn('Купить', '')(class='card__buy')
                

Лейбл

Текст1
Текст2
Текст3
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (label)
                   
                  mixin label(text, mods, tag)
                   
                    //- Принимает:
                    //-   text  {string} - текст кнопки
                    //-   mods  {string} - список модификаторов
                    //-   tag   {string} - тег (если не span)
                    //- Вызов:
                          +label('Лейбл')
                          +label('Лейбл', 'danger', 'div')
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' label--' + modsList[i].trim();
                        }
                      }
                   
                    if(typeof(tag) !== 'undefined' && tag)
                      #{tag}.label(class=allMods)&attributes(attributes)!= text
                        block
                    else
                      span.label(class=allMods)&attributes(attributes)!= text
                

Загрузчик

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (loader)
                   
                  mixin loader(mods)
                   
                    //- Принимает:
                    //-   mods  {string} - список модификаторов
                    //- Вызов:
                          +loader()
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' loader--' + modsList[i].trim();
                        }
                      }
                   
                    span.loader(class=allMods)&attributes(attributes)
                

Пагинация

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (pagination)
                   
                  mixin pagination(mods)
                   
                    //- Принимает:
                    //-   mods  {string} - список модификаторов
                    //- Вызов:
                          +pagination()
                            +pagination-item('1', '/1')
                            +pagination-item('...')
                            +pagination-item('4', '/4')
                            +pagination-item('5', '/5', true)
                            +pagination-item('6', '/6')
                            +pagination-item('...')
                            +pagination-item('999', '/999')
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' pagination--' + modsList[i].trim();
                        }
                      }
                   
                    .pagination(class=allMods, aria-label='Page navigation')&attributes(attributes)
                      block
                   
                   
                   
                  mixin pagination-item(text, href, active, mods)
                   
                    //- Принимает:
                    //-   text   {string} - содержимое пункта
                    //-   href   {string} - ссылка этого пункта (если пустая, то это не ссылка, а span)
                    //-   active {bool}   - флаг «это активный пункт»
                    //-   mods   {string} - список модификаторов
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' pagination__item--' + modsList[i].trim();
                        }
                      }
                      if(typeof(active) !== 'undefined' && active) {
                        allMods = allMods + ' pagination__item--active';
                      }
                   
                    if(typeof(href) !== 'undefined' && href)
                      a.pagination__item(class=allMods, href=href)&attributes(attributes)!= text
                    else
                      span.pagination__item(class=allMods)&attributes(attributes)!= text
                

Прогресс

30% (без копеек)
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (progress)
                   
                  mixin progress(percent, text, mods)
                   
                    //- Принимает:
                    //-   percent  {string} - процент заполнения
                    //-   text     {string} - текст на заполненной части (если пуст, текстового узда не будет)
                    //-   mods     {string} - список модификаторов
                    //- Вызов:
                          +progress('30', '30%', 'success')(aria-valuemin='0', aria-valuemax='100')
                          +progress('10')(style='height: 10px')
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' progress--' + modsList[i].trim();
                        }
                      }
                   
                    .progress(class=allMods)
                      .progress__bar(role='progressbar', style='width: ' + percent + '%;', aria-valuenow=percent)&attributes(attributes)
                        if(typeof(text) !== 'undefined' && text)
                          span.progress__bartext!= text
                

Комментарий

Джокер
Джокер

Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.

Джокересса
Джокересса

Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.

Джокер 2
Джокер 2

Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.

Джокер
Джокер

Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (comment)
                   
                  mixin comment(props)
                   
                    //- Принимает:
                    //-   props  {object}
                    //-     username  {string} - имя пользователя
                    //-     avatarURL {string} - адрес изображения с аватаром
                    //-     authorURL {string} - адрес изображения с аватаром
                    //-     content   {string} - html текста коммента
                    //-     mods      {string} - список модификаторов
                    //- Вызов:
                          +comment({
                            username: 'Джокер',
                            avatarURL: 'img/joker.jpg',
                            authorURL: '/users/joker',
                            content: '<p>Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.</p>',
                            mods: 'admin',
                          })
                            +comment({
                              username: 'Докер',
                              content: '<p>Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.</p>',
                            })
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(props.mods) !== 'undefined' && props.mods) {
                        var modsList = props.mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' comment--' + modsList[i].trim();
                        }
                      }
                      if(typeof(props.username) === 'undefined') props.username = 'anonymous';
                      if(typeof(props.avatarURL) === 'undefined') props.avatarURL = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60"%3E%3Ccircle r="50%25" cx="50%25" cy="50%25" fill="#ccc"/%3E%3C/svg%3E';
                   
                    article.comment(class=allMods)&attributes(attributes)
                      .comment__inner
                        if(typeof(props.authorURL) !== 'undefined' && props.authorURL)
                          a.comment__avatar-wrap(href=props.authorURL)
                            img(src=props.avatarURL, alt=props.username)
                        else
                          span.comment__avatar-wrap
                            img(src=props.avatarURL, alt=props.username)
                        .comment__text
                          header.comment__header #[b.comment__author= props.username] #[time.comment__date(datetime='2017-04-25T05:45') 25.04.2017 в 05:45]
                          .comment__body!= props.content
                          footer.comment__footer.
                            #[a.comment__reply(href='') Reply] #[a.comment__reply(href='') Admin]
                      block
                

Социальные ссылки

Социальные ссылки. Изображения иконок лучше хранить в SVG-спрайте.

По умолчанию оставлены только стили для facebook, прочие закомментированы. См. social/social.scss.

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (social)
                   
                  mixin social(mods)
                   
                    //- Принимает:
                    //-   mods: ''          {string} - модификаторы блока
                    //- Вызов:
                          +social()
                            +social-link('https://www.facebook.com/profile.php?id=100011672930358', 'fb')(title='Facebook')
                              svg(xmlns='http://www.w3.org/2000/svg', width='16', height='16', viewBox='0 0 470.513 470.513')
                                path(d='M271.521 154.17v-40.541c0-6.086.28-10.8.849-14.13.567-3.335 1.857-6.615 3.859-9.853 1.999-3.236 5.236-5.47 9.706-6.708 4.476-1.24 10.424-1.858 17.85-1.858h40.539V0h-64.809c-37.5 0-64.433 8.897-80.803 26.691-16.368 17.798-24.551 44.014-24.551 78.658v48.82h-48.542v81.086h48.539v235.256h97.362V235.256h64.805l8.566-81.086h-73.37z')
                            +social-link('https://vk.com/n.gromov', 'vk')(title='ВКонтакте')
                              svg(xmlns='http://www.w3.org/2000/svg', width='16', height='16', viewBox='0 0 548.358 548.358')
                                path(d='M545.451 400.298c-.664-1.431-1.283-2.618-1.858-3.569-9.514-17.135-27.695-38.167-54.532-63.102l-.567-.571-.284-.28-.287-.287h-.288c-12.18-11.611-19.893-19.418-23.123-23.415-5.91-7.614-7.234-15.321-4.004-23.13 2.282-5.9 10.854-18.36 25.696-37.397 7.807-10.089 13.99-18.175 18.556-24.267 32.931-43.78 47.208-71.756 42.828-83.939l-1.701-2.847c-1.143-1.714-4.093-3.282-8.846-4.712-4.764-1.427-10.853-1.663-18.278-.712l-82.224.568c-1.332-.472-3.234-.428-5.712.144l-3.713.859-1.431.715-1.136.859c-.952.568-1.999 1.567-3.142 2.995-1.137 1.423-2.088 3.093-2.848 4.996-8.952 23.031-19.13 44.444-30.553 64.238-7.043 11.803-13.511 22.032-19.418 30.693-5.899 8.658-10.848 15.037-14.842 19.126-4 4.093-7.61 7.372-10.852 9.849-3.237 2.478-5.708 3.525-7.419 3.142-1.715-.383-3.33-.763-4.859-1.143-2.663-1.714-4.805-4.045-6.42-6.995-1.622-2.95-2.714-6.663-3.285-11.136-.568-4.476-.904-8.326-1-11.563-.089-3.233-.048-7.806.145-13.706.198-5.903.287-9.897.287-11.991 0-7.234.141-15.085.424-23.555.288-8.47.521-15.181.716-20.125.194-4.949.284-10.185.284-15.705s-.336-9.849-1-12.991a44.442 44.442 0 0 0-2.99-9.137c-1.335-2.95-3.289-5.232-5.853-6.852-2.569-1.618-5.763-2.902-9.564-3.856-10.089-2.283-22.936-3.518-38.547-3.71-35.401-.38-58.148 1.906-68.236 6.855-3.997 2.091-7.614 4.948-10.848 8.562-3.427 4.189-3.905 6.475-1.431 6.851 11.422 1.711 19.508 5.804 24.267 12.275l1.715 3.429c1.334 2.474 2.666 6.854 3.999 13.134 1.331 6.28 2.19 13.227 2.568 20.837.95 13.897.95 25.793 0 35.689-.953 9.9-1.853 17.607-2.712 23.127-.859 5.52-2.143 9.993-3.855 13.418-1.715 3.426-2.856 5.52-3.428 6.28-.571.76-1.047 1.239-1.425 1.427a21.387 21.387 0 0 1-7.71 1.431c-2.667 0-5.901-1.334-9.707-4-3.805-2.666-7.754-6.328-11.847-10.992-4.093-4.665-8.709-11.184-13.85-19.558-5.137-8.374-10.467-18.271-15.987-29.691l-4.567-8.282c-2.855-5.328-6.755-13.086-11.704-23.267-4.952-10.185-9.329-20.037-13.134-29.554-1.521-3.997-3.806-7.04-6.851-9.134l-1.429-.859c-.95-.76-2.475-1.567-4.567-2.427a30.301 30.301 0 0 0-6.567-1.854l-78.229.568c-7.994 0-13.418 1.811-16.274 5.428l-1.143 1.711c-.571.953-.859 2.475-.859 4.57 0 2.094.571 4.664 1.714 7.707 11.42 26.84 23.839 52.725 37.257 77.659 13.418 24.934 25.078 45.019 34.973 60.237 9.897 15.229 19.985 29.602 30.264 43.112 10.279 13.515 17.083 22.176 20.412 25.981 3.333 3.812 5.951 6.662 7.854 8.565l7.139 6.851c4.568 4.569 11.276 10.041 20.127 16.416 8.853 6.379 18.654 12.659 29.408 18.85 10.756 6.181 23.269 11.225 37.546 15.126 14.275 3.905 28.169 5.472 41.684 4.716h32.834c6.659-.575 11.704-2.669 15.133-6.283l1.136-1.431c.764-1.136 1.479-2.901 2.139-5.276.668-2.379 1-5 1-7.851-.195-8.183.428-15.558 1.852-22.124 1.423-6.564 3.045-11.513 4.859-14.846 1.813-3.33 3.859-6.14 6.136-8.418 2.282-2.283 3.908-3.666 4.862-4.142.948-.479 1.705-.804 2.276-.999 4.568-1.522 9.944-.048 16.136 4.429 6.187 4.473 11.99 9.996 17.418 16.56 5.425 6.57 11.943 13.941 19.555 22.124 7.617 8.186 14.277 14.271 19.985 18.274l5.708 3.426c3.812 2.286 8.761 4.38 14.853 6.283 6.081 1.902 11.409 2.378 15.984 1.427l73.087-1.14c7.229 0 12.854-1.197 16.844-3.572 3.998-2.379 6.373-5 7.139-7.851.764-2.854.805-6.092.145-9.712-.677-3.611-1.344-6.136-2.008-7.563z')
                            +social-link('https://github.com/nicothin', 'gh')(title='Github')
                              svg(xmlns='http://www.w3.org/2000/svg', width='16', height='16', viewBox='0 0 475.084 475.084')
                                path(d='M436.244 146.752c5.14-15.422 7.713-31.409 7.713-47.967 0-22.08-4.859-42.828-14.564-62.242-20.362 0-38.349 3.715-53.961 11.136-15.604 7.423-33.4 18.938-53.379 34.545-25.122-6.09-51.777-9.135-79.941-9.135-30.837 0-60.245 3.333-88.223 9.994-20.364-15.99-38.351-27.74-53.959-35.26-15.608-7.52-33.689-11.279-54.247-11.279-9.707 19.414-14.56 40.163-14.56 62.242 0 16.751 2.568 32.93 7.708 48.535C12.942 177.587 0 215.272 0 260.383c0 39.595 5.898 71.092 17.701 94.507 6.283 12.367 14.465 23.312 24.554 32.832 10.085 9.514 21.601 17.228 34.545 23.13 12.946 5.896 25.981 10.801 39.116 14.699 13.134 3.9 27.646 6.758 43.54 8.559 15.893 1.816 29.93 3.004 42.111 3.579 12.181.564 25.693.853 40.544.853 17.508 0 33.396-.432 47.678-1.283 14.277-.855 30.594-2.953 48.964-6.276 18.367-3.333 34.547-7.857 48.54-13.565 13.99-5.708 27.412-13.895 40.259-24.551 12.847-10.663 22.884-23.318 30.121-37.976 11.604-23.603 17.412-55.107 17.412-94.507-.007-45.302-12.95-83.178-38.841-113.632zm-34.249 207.703c-6.092 12.471-13.802 22.265-23.127 29.41-9.329 7.139-20.938 12.847-34.831 17.135-13.9 4.281-27.217 7.087-39.971 8.415-12.758 1.334-26.933 1.998-42.545 1.998h-47.966c-15.607 0-29.79-.664-42.541-1.998-12.752-1.328-26.075-4.134-39.971-8.415-13.891-4.288-25.5-9.996-34.829-17.135-9.329-7.146-17.037-16.939-23.128-29.41-6.09-12.471-9.136-27.076-9.136-43.824 0-22.847 6.567-42.264 19.702-58.245 13.134-15.99 30.929-23.982 53.387-23.982 8.188 0 26.746 1.997 55.677 5.995 13.513 2.093 28.456 3.14 44.823 3.14 16.372 0 31.313-1.044 44.824-3.14 29.317-3.999 47.869-5.995 55.678-5.995 22.457 0 40.252 7.996 53.386 23.982 13.135 15.988 19.698 35.398 19.698 58.245 0 16.751-3.046 31.364-9.13 43.824z')
                                path(d='M166.875 265.52c-5.806-6.475-12.703-9.712-20.699-9.712-7.998 0-14.896 3.241-20.701 9.712-5.802 6.468-9.897 13.703-12.275 21.689-2.383 8.002-3.571 15.804-3.571 23.422 0 7.61 1.191 15.413 3.571 23.414 2.375 7.991 6.468 15.222 12.275 21.689 5.808 6.475 12.703 9.713 20.701 9.713 7.996 0 14.896-3.244 20.699-9.713 5.804-6.468 9.897-13.698 12.275-21.689 2.38-8.001 3.571-15.804 3.571-23.414 0-7.611-1.188-15.42-3.571-23.422-2.379-7.983-6.468-15.215-12.275-21.689zM349.601 265.52c-5.804-6.475-12.703-9.712-20.697-9.712-7.991 0-14.894 3.241-20.701 9.712-5.804 6.468-9.896 13.703-12.271 21.689-2.385 8.002-3.576 15.804-3.576 23.422 0 7.61 1.191 15.413 3.576 23.414 2.375 7.991 6.468 15.222 12.271 21.689 5.808 6.475 12.71 9.713 20.701 9.713 7.994 0 14.894-3.244 20.697-9.713 5.801-6.468 9.896-13.698 12.278-21.689 2.379-8.001 3.569-15.804 3.569-23.414 0-7.611-1.19-15.42-3.569-23.422-2.381-7.983-6.477-15.215-12.278-21.689z')
                            +social-link('https://twitter.com/nicothin', 'tw')(title='twitter')
                              svg(xmlns='http://www.w3.org/2000/svg', width='16', height='16', viewBox='0 0 449.956 449.956')
                                path(d='M449.956 85.657c-17.702 7.614-35.408 12.369-53.102 14.279 19.985-11.991 33.503-28.931 40.546-50.819-18.281 10.847-37.787 18.268-58.532 22.267-18.274-19.414-40.73-29.125-67.383-29.125-25.502 0-47.246 8.992-65.24 26.98-17.984 17.987-26.977 39.731-26.977 65.235 0 6.851.76 13.896 2.284 21.128-37.688-1.903-73.042-11.372-106.068-28.407C82.46 110.158 54.433 87.46 31.403 59.101c-8.375 14.272-12.564 29.787-12.564 46.536 0 15.798 3.711 30.456 11.138 43.97 7.422 13.512 17.417 24.455 29.98 32.831-14.849-.572-28.743-4.475-41.684-11.708v1.142c0 22.271 6.995 41.824 20.983 58.674 13.99 16.848 31.645 27.453 52.961 31.833a95.543 95.543 0 0 1-24.269 3.138c-5.33 0-11.136-.475-17.416-1.42 5.9 18.459 16.75 33.633 32.546 45.535 15.799 11.896 33.691 18.028 53.677 18.418-33.498 26.262-71.66 39.393-114.486 39.393-8.186 0-15.607-.373-22.27-1.139 42.827 27.596 90.03 41.394 141.612 41.394 32.738 0 63.478-5.181 92.21-15.557 28.746-10.369 53.297-24.267 73.665-41.686 20.362-17.415 37.925-37.448 52.674-60.097 14.75-22.651 25.738-46.298 32.977-70.946 7.23-24.653 10.848-49.344 10.848-74.092 0-5.33-.096-9.325-.287-11.991 18.087-13.127 33.504-29.023 46.258-47.672z')
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' social--' + modsList[i].trim();
                        }
                      }
                   
                    ul.social(class=allMods)&attributes(attributes)
                      block
                   
                  mixin social-link(link, mods)
                   
                    //- Принимает:
                    //-   link     {string} - ссылка
                    //-   mods     {string} - список модификаторов
                    //- Вызов:
                          +social-link('https://vk.com/n.gromov', 'some-mod')
                            span ВКонтакте
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' social__link-wrap--' + modsList[i].trim();
                        }
                      }
                   
                    li.social__link-wrap(class=allMods)&attributes(attributes)
                      a.social__link(href=link)
                        block
                

Разделитель «или»

или
Текст взамен «или»
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (or)
                   
                  mixin or(text, mods)
                   
                    //- Принимает:
                    //-   text    {string} - текст
                    //-   mods    {string} - список модификаторов
                    //- Вызов:
                          +or('Текст', 'some-mod')
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' or--' + modsList[i].trim();
                        }
                      }
                      if(typeof(text) === 'undefined')
                        text = 'или'
                   
                    .or(class=allMods)&attributes(attributes)
                      .or__inner!= text
                

Адаптирующийся медиаконтент

По умолчанию предназначен для встраивания роликов 16:9. C модификатором позволяет встраивать ролики 4:3.

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (embed-responsive)
                   
                  mixin embed-responsive(mods)
                   
                    //- Принимает:
                    //-   mods    {string} - список модификаторов
                    //- Вызов:
                          +embed-responsive()
                            iframe(src='https://www.youtube.com/embed/B0Q1rKpDNE4', frameborder='0', allowfullscreen='')
                          +embed-responsive('4-3')
                            iframe(src='https://www.youtube.com/embed/7pOr3dBFAeY', frameborder='0', allowfullscreen='')
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' embed-responsive--' + modsList[i].trim();
                        }
                      }
                   
                    .embed-responsive(class=allMods)&attributes(attributes)
                      block
                

Таблица

Имя Фамилия Мыло Статус Политическая ориентация
Иннокентий Иванов Хозяйственное Администратор «ВСЕГДА!»
Васисуалий Римский-Корсаков Душистое Пользователь Нижняя
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (table)
                   
                  mixin table(mods)
                   
                    //- Принимает:
                    //-   mods  {string} - список модификаторов
                    //- Вызов:
                          +table()
                            tr
                              th Имя
                              th Фамилия
                              th Мыло
                            tr
                              td Иннокентий
                              td Иванов
                              td Хозяйственное
                            tr
                              td Васисуалий
                              td Римский-Корсаков
                              td Душистое
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' table--' + modsList[i].trim();
                        }
                      }
                   
                    table.table(class=allMods)&attributes(attributes)
                      block
                

Адаптивная таблица

Требует добавления атрибутов data-label для каждой ячейки, написания thead и tbody, хорошо работает только при горизонтальном расположении заголовочных ячеек.

Таблица
Имя и фамилия Тип мироощущения
Анатоле Вассерман Девственность
Джакомо Казанова Небольшая распущенность с лёгкой примесью леденящих душу извращений, чудовищной лжи и имитатора известного органа, обитого телячьей кожей.
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (table-responsive)
                   
                  mixin table-responsive(mods)
                   
                    //- Принимает:
                    //-   mods  {string} - список модификаторов
                    //- Вызов:
                          +table-responsive()
                            thead
                              tr
                                th Имя и фамилия
                                th Тип мироощущения
                            tbody
                              tr
                                td(data-label='Имя и фамилия') Анатоле Вассерман
                                td(data-label='Тип мироощущения') Девственность
                              tr
                                td(data-label='Имя и фамилия') Джакомо Казанова
                                td(data-label='Тип мироощущения') Небольшая распущенность с лёгкой примесью леденящих душу извращений, чудовищной лжи и имитатора известного органа, обитого телячьей кожей.
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' table-responsive--' + modsList[i].trim();
                        }
                      }
                   
                    table.table-responsive(class=allMods)&attributes(attributes)
                      block
                

Код

Оформление блочных вставок кода.

<div class="some">...</div>
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (code)
                   
                  mixin code()
                   
                    //- Вызов:
                          +code()
                            code <div class="some">...</div>
                            code <div class="some">...</div>
                   
                    pre.code&attributes(attributes)
                      block
                

Кнопка

Кнопка-ссылка

Кнопка-ссылка

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (btn)
                   
                  mixin btn(text, mods, isInput)
                   
                    //- Принимает:
                    //-   text    {string} - текст кнопки
                    //-   mods    {string} - список модификаторов
                    //-   isInput {bool}   - флаг «это тег input»
                    //- Вызов:
                          +btn('Кнопка-ссылка')(href='/')  - есть href, это точно ссылка
                          +btn('Кнопка-input', '', true)   - есть флаг isInput, это input
                          +btn('Кнопка-button', 'success') - нет href, нет isInput — это button
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' btn--' + modsList[i].trim();
                        }
                      }
                   
                    //- передан href — это ссылка
                    if (attributes.href)
                      a.btn(class=allMods)&attributes(attributes)!= text
                        block
                   
                    //- иначе, если передан isInput и он true, это input
                    else if (typeof(isInput) !== 'undefined' && isInput)
                      input.btn(class=allMods, value=text, type='button')&attributes(attributes)
                   
                    //- иначе это button
                    else
                      button.btn(class=allMods)&attributes(attributes)!= text
                        block
                

Текстовое поле

Текстовые поля любого типа. В том числе, с использованием не input, а textarea. Для textarea использован autosize.

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-text)
                   
                  mixin field-text(props)
                   
                    //- Принимает:
                    //-   props {
                    //-     title: ''         {string} - текст с названием (выводится над полем)
                    //-     isTextarea: false {bool}   - флаг input/textarea
                    //-     helpText: ''      {string} - пояснение под полем
                    //-     mods: ''          {string} - модификаторы блока
                    //-     val: ''           {string} - текст в поле
                    //-     attrs:            {object} - любые атрибуты для input/textarea
                    //-       type:           {string}
                    //-       placeholder:    {string}
                    //- Вызов:
                          +field-text({
                            title: 'Название',
                            isTextarea: true,
                            helpText: 'Подсказка',
                            mods: '',
                            val: '',
                            attrs: {
                              name: 'comment',
                            }
                          })
                   
                    -
                      if(typeof(props) === 'undefined') {
                        var props = {};
                      }
                      var allMods = '';
                      if(typeof(props.mods) !== 'undefined' && props.mods) {
                        var modsList = props.mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' field-text--' + modsList[i].trim();
                        }
                      }
                   
                    label.field-text(class=allMods)&attributes(attributes)
                      if(typeof(props.title) !== 'undefined' && props.title)
                        span.field-text__name!= props.title
                      span.field-text__input-wrap
                        if(typeof(props.isTextarea) !== 'undefined' && props.isTextarea)
                          textarea.field-text__input&attributes(props.attrs)= props.val
                        else
                          input.field-text__input(type=(typeof(props.attrs) !== 'undefined' && props.attrs.type) ? props.attrs.type : 'text', value=props.val)&attributes(props.attrs)
                        if(typeof(props.helpText) !== 'undefined' && props.helpText)
                          span.field-text__help-text!= props.helpText
                        block
                

Выбор количества

Количество От 1 до 10, шаг 1
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-num)
                   
                  mixin field-num(props)
                   
                    //- Принимает:
                    //-   props {
                    //-     title: ''         {string} - текст с названием (выводится над полем)
                    //-     helpText: ''      {string} - пояснение под полем
                    //-     mods: ''          {string} - модификаторы блока
                    //-     val:              {number} - количество в поле
                    //-     attrs:            {object} - любые атрибуты для input
                    //-       placeholder:    {string}
                    //- Вызов:
                          +field-num({
                            title: 'Количество',
                            helpText: 'От 1 до 10, шаг 1',
                            mods: '',
                            val: '9',
                            attrs: {
                              name: 'quantity',
                              max: '10',
                              min: '1',
                              step: '1',
                            }
                          })
                          +field-num({
                            mods: 'error',
                            attrs: {
                              name: 'quantity',
                            }
                          })
                   
                    -
                      if(typeof(props) === 'undefined') { var props = {}; }
                      var allMods = '';
                      if(typeof(props.mods) !== 'undefined' && props.mods) {
                        var modsList = props.mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' field-num--' + modsList[i].trim();
                        }
                      }
                      if(props.attrs.disabled) allMods = allMods + ' field-num--disabled';
                      var val = parseInt(props.val);
                      if(isNaN(val)) val = 0;
                   
                    .field-num(class=allMods)&attributes(attributes)
                      if(typeof(props.title) !== 'undefined' && props.title)
                        span.field-num__name!= props.title
                      span.field-num__input-wrap
                        span.field-num__input-and-btns
                          button.field-num__btn.field-num__btn--minus(type='button') -
                          button.field-num__btn.field-num__btn--plus(type='button') +
                          input.field-num__input(type='number', value=val)&attributes(props.attrs)
                        if(typeof(props.helpText) !== 'undefined' && props.helpText)
                          span.field-num__help-text!= props.helpText
                        block
                

Флажок/чекбокс

В стилевом файле есть закомментированные фрагменты для замены нативного элемента своим (svg).

Отдельно расположенный чекбокс
Общее необязательное название
И, возможно, единственный
А, нет. Не единственный...
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-checkbox)
                   
                  mixin field-checkbox(checkboxes, title)
                   
                    //- Принимает:
                    //-   checkboxes {array}
                    //-     {object}
                    //-       title: ''         {string} - текст рядом с чекбоксом
                    //-       helpText: ''      {string} - пояснение под полем
                    //-       mods: ''          {string} - модификаторы обертки чекбокса
                    //-       attrs:            {object} - любые атрибуты для input
                    //-         name:           {string}
                    //-     ...
                    //- Вызов:
                          +field-checkbox([
                            {
                              title: 'Чекбокс0',
                              helpText: 'Подсказка',
                              attrs: {
                                name: 'check0',
                              }
                            },
                          ])
                          +field-checkbox([
                            {
                              title: 'Чекбокс1',
                              helpText: 'Подсказка',
                              mods: 'error',
                              attrs: {
                                name: 'check1',
                                checked: true,
                              }
                            },
                            {
                              title: 'Чекбокс2',
                              helpText: 'Подсказка',
                              mods: 'error',
                              attrs: {
                                name: 'check2',
                              }
                            },
                          ], 'ОбщееНазваниеБлока')
                   
                    .field-checkbox&attributes(attributes)
                      if(typeof(title) !== 'undefined' && title)
                        .field-checkbox__title!= title
                      each checkbox in checkboxes
                        -
                          var allMods = '';
                          if(typeof(checkbox.mods) !== 'undefined' && checkbox.mods) {
                            var modsList = checkbox.mods.split(',');
                            for (var i = 0; i < modsList.length; i++) {
                              allMods = allMods + ' field-checkbox__input-wrap--' + modsList[i].trim();
                            }
                          }
                        .field-checkbox__input-wrap(class=allMods)
                          label.field-checkbox__name
                            input.field-checkbox__input(type='checkbox')&attributes(checkbox.attrs)
                            span.field-checkbox__name-text!= checkbox.title
                          if(typeof(checkbox.helpText) !== 'undefined' && checkbox.helpText)
                            .field-checkbox__help-text-wrap
                              .field-checkbox__help-text!= checkbox.helpText
                

Радиокнопки

В стилевом файле есть закомментированные фрагменты для замены нативного элемента своим (svg).

Общее необязательное название
И, возможно, единственный
А, нет. Не единственный...
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-radio)
                   
                  mixin field-radio(radiobuttons, title)
                   
                    //- Принимает:
                    //-   radiobuttons {array}
                    //-     {object}
                    //-       title: ''         {string} - текст рядом с радиокнопкой
                    //-       helpText: ''      {string} - пояснение под полем
                    //-       mods: ''          {string} - модификаторы обертки радиокнопки
                    //-       attrs:            {object} - любые атрибуты для input
                    //-         name:           {string}
                    //-         ...
                    //- Вызов:
                          +field-radio([
                            {
                              title: 'Радиокнопка1',
                              helpText: 'Подсказка',
                              mods: '',
                              attrs: {
                                name: 'radio',
                                checked: true,
                              }
                            },
                            {
                              title: 'Радиокнопка2',
                              helpText: 'Подсказка',
                              mods: '',
                              attrs: {
                                name: 'radio',
                              }
                            },
                          ], 'ОбщееНазваниеБлока')
                   
                    .field-radio&attributes(attributes)
                      if(typeof(title) !== 'undefined' && title)
                        .field-radio__title!= title
                      each checkbox in radiobuttons
                        -
                          var allMods = '';
                          if(typeof(checkbox.mods) !== 'undefined' && checkbox.mods) {
                            var modsList = checkbox.mods.split(',');
                            for (var i = 0; i < modsList.length; i++) {
                              allMods = allMods + ' field-radio__input-wrap--' + modsList[i].trim();
                            }
                          }
                        .field-radio__input-wrap(class=allMods)
                          label.field-radio__name
                            input.field-radio__input(type='radio')&attributes(checkbox.attrs)
                            span.field-radio__name-text!= checkbox.title
                          if(typeof(checkbox.helpText) !== 'undefined' && checkbox.helpText)
                            .field-radio__help-text-wrap
                              .field-radio__help-text!= checkbox.helpText
                

Переключатель

Это чекбокс, на самом деле
Это чекбокс, на самом деле
Это чекбокс, на самом деле
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-toggler)
                   
                  mixin field-toggler(togglers, title, isRadio)
                   
                    //- Принимает:
                    //-   togglers {array}
                    //-     {object}
                    //-       title: ''         {string} - текст рядом с переключателем
                    //-       helpText: ''      {string} - пояснение под полем
                    //-       mods: ''          {string} - модификаторы обёртки переключателя
                    //-       attrs:            {object} - любые атрибуты для input
                    //-         name:           {string}
                    //-     ...
                    //-   title: ''             {string} - общее название группы переключателей
                    //-   isRadio: false        {bool}   - флаг «это радиокнопки, а не чекбоксы»
                    //- Вызов:
                          +field-toggler([
                            {
                              title: 'Переключатель0',
                              helpText: 'Подсказка',
                              attrs: {
                                name: 'check0',
                              }
                            },
                          ])
                          +field-toggler([
                            {
                              title: 'Переключатель1',
                              helpText: 'Подсказка',
                              attrs: {
                                name: 'check1',
                                checked: true,
                              }
                            },
                            {
                              title: 'Переключатель2',
                              helpText: 'Подсказка',
                              mods: 'some',
                              attrs: {
                                name: 'check2',
                              }
                            },
                          ], 'ОбщееНазваниеБлока', true)
                   
                    -
                      if(typeof(isRadio) !== 'undefined' && isRadio)
                        var type = 'radio';
                      else
                        var type = 'checkbox';
                   
                    .field-toggler&attributes(attributes)
                      if(typeof(title) !== 'undefined' && title)
                        .field-toggler__title!= title
                      each toggler in togglers
                        -
                          var allMods = '';
                          if(typeof(toggler.mods) !== 'undefined' && toggler.mods) {
                            var modsList = toggler.mods.split(',');
                            for (var i = 0; i < modsList.length; i++) {
                              allMods = allMods + ' field-toggler__input-wrap--' + modsList[i].trim();
                            }
                          }
                        .field-toggler__input-wrap(class=allMods)
                          label.field-toggler__name
                            input.field-toggler__input(type=type)&attributes(toggler.attrs)
                            span.field-toggler__name-text!= toggler.title
                          if(typeof(toggler.helpText) !== 'undefined' && toggler.helpText)
                            .field-toggler__help-text-wrap
                              .field-toggler__help-text!= toggler.helpText
                

Файл

Название
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-file)
                   
                  mixin field-file(props)
                   
                    //- Принимает:
                    //-   props {object}
                    //-     title: ''           {string} - текст с названием (выводится над полем)
                    //-     helpText: ''        {string} - пояснение под полем
                    //-     mods: ''            {string} - модификаторы блока
                    //-     attrs:              {object} - любые атрибуты для input
                    //-       name:             {string}
                    //-     text:               {object} - тексты
                    //-       selectText:       {string} - текст на кнопке «выберите файл(ы)»
                    //-       nothingText:      {string} - текст, показываемый, пока ничего не выбрано
                    //-       flesSelectedText: {string} - текст, показываемый, если выбрано более одного файла («файлов выбрано: 2»)
                    //- Вызов:
                          +field-file({
                            title: 'Название',
                            helpText: 'Подсказка',
                            mods: '',
                            attrs: {
                              name: 'commentFile',
                              multiple: true,
                            },
                            text: {
                              selectText: 'Выберите файл(ы)',
                              nothingText: 'Ничего не выбрано',
                              flesSelectedText: 'Выбрано файлов:',
                            },
                          })
                   
                    -
                      if(typeof(props) === 'undefined') {
                        var props = {};
                      }
                      var allMods = '';
                      if(typeof(props.mods) !== 'undefined' && props.mods) {
                        var modsList = props.mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' field-file--' + modsList[i].trim();
                        }
                      }
                   
                      var selectText = 'Выберите файл(ы)'; // Select file(s)
                      var nothingText = ''; // Nothing selected
                      var flesSelectedText = 'Выбрано файлов: {count}'; // Selected files: {count}
                   
                      if (typeof(props.text) !== 'undefined' && props.text !== '') {
                        if (typeof(props.text.selectText) !== 'undefined') selectText = props.text.selectText;
                        if (typeof(props.text.nothingText) !== 'undefined') nothingText = props.text.nothingText;
                        if (typeof(props.text.flesSelectedText) !== 'undefined') flesSelectedText = props.text.flesSelectedText + ' {count}';
                      }
                   
                    .field-file(class=allMods)&attributes(attributes)
                      if(typeof(props.title) !== 'undefined' && props.title)
                        .field-file__name!= props.title
                      label.field-file__input-wrap
                        input.field-file__input(type='file', data-multiple-caption=flesSelectedText)&attributes(props.attrs)
                        .field-file__name-text(data-button-text=selectText)= nothingText
                        if(typeof(props.helpText) !== 'undefined' && props.helpText)
                          .field-file__help-text!= props.helpText
                        block
                

Ползунок

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-range)
                   
                  mixin field-range(props)
                   
                    //- Принимает:
                    //-   props {object}
                    //-     title: ''         {string} - текст с названием (выводится над полем)
                    //-     helpText: ''      {string} - пояснение под полем
                    //-     mods: ''          {string} - модификаторы блока
                    //-     attrs:            {object} - любые атрибуты для input
                    //-       name:           {string}
                    //- Вызов:
                          +field-range({
                            title: 'Название',
                            helpText: 'Подсказка',
                            mods: '',
                            attrs: {
                              name: 'counter',
                              min: '1',
                              max: '100',
                              step: '1',
                              value: '40',
                            }
                          })
                   
                    -
                      if(typeof(props) === 'undefined') {
                        var props = {};
                      }
                      var allMods = '';
                      if(typeof(props.mods) !== 'undefined' && props.mods) {
                        var modsList = props.mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' field-range--' + modsList[i].trim();
                        }
                      }
                   
                    label.field-range(class=allMods)&attributes(attributes)
                      if(typeof(props.title) !== 'undefined' && props.title)
                        span.field-range__name!= props.title
                      span.field-range__input-wrap
                        input.field-range__input(type='range')&attributes(props.attrs)
                        if(typeof(props.helpText) !== 'undefined' && props.helpText)
                          span.field-range__help-text!= props.helpText
                        block
                

Кастомный селект с Choices

Название селекта
Подсказка
Название селекта
Подсказка
Название селекта
Подсказка
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-select)
                   
                  mixin field-select(title, attrs, options, helpText, mods)
                   
                    //- Принимает:
                    //-   title: ''         {string} - название селекта
                    //-   attrs:            {object} - атрибуты селекта
                    //-     name: ''        {string}
                    //-   options {array}
                    //-     {object}
                    //-       title: ''     {string} - текст пункта
                    //-       attrs:        {object} - любые атрибуты пункта
                    //-         value:      {string}
                    //-     {object}
                    //-       attrs:        {object} - любые атрибуты пункта
                    //-         label:      {string}
                    //-       child:        {array}  - потомки (если есть этот элемент, то его родитель — optgroup)
                    //-         {object}
                    //-           title: '' {string}
                    //-           attrs:    {object}
                    //-             value:  {string}
                    //-     {object}
                    //-       title: ''     {string} - текст пункта
                    //-       attrs:        {object} - любые атрибуты пункта
                    //-         value:      {string}
                    //-   helpText: ''      {string} - текст подсказки
                    //-   mods: ''          {string} - модификаторы блока
                    //- Вызов:
                          +field-select(
                            'Название',
                            {
                              name: 'select',
                              id: 'select'
                            },
                            [
                              {
                                title: 'Опция1',
                                attrs: {
                                  value: '',
                                }
                              },
                              {
                                title: 'Опция2',
                                attrs: {
                                  value: '',
                                }
                              },
                            ],
                            'Подсказка',
                            ''
                          )
                          +field-select(
                            'Название',
                            {
                              name: '',
                              id: ''
                            },
                            [
                              {
                                attrs: {
                                  label: 'Группа',
                                },
                                child: [
                                  {
                                    title: 'Опция1',
                                    attrs: {
                                      value: 'val01',
                                    }
                                  },
                                  {
                                    title: 'Опция2',
                                    attrs: {
                                      value: 'val02',
                                    }
                                  },
                                ]
                              },
                              {
                                title: 'Опция3',
                                attrs: {
                                  value: 'val03',
                                }
                              }
                            ],
                            'Подсказка',
                            ''
                          )
                   
                    -
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' field-select--' + modsList[i].trim();
                        }
                      }
                   
                    .field-select(class=allMods)&attributes(attributes)
                      if(typeof(title) !== 'undefined' && title)
                        .field-select__name!= title
                      .field-select__select-wrap
                        select.field-select__select&attributes(attrs)
                          each option in options
                            //- option= option
                            if(typeof(option.child) !== 'undefined' && option.child)
                              optgroup(label=option.attrs.label)
                                each subOption in option.child
                                  option&attributes(subOption.attrs)= subOption.title
                            else if(typeof(option.title) !== 'undefined' && option.title)
                              option&attributes(option.attrs)= option.title
                        if(typeof(helpText) !== 'undefined' && helpText)
                          span.field-select__help-text!= helpText
                

Действия формы

* — обязательные поля
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (field-actions)
                   
                  mixin field-actions(text, mods)
                   
                    //- Принимает:
                    //-     text: ''  {string} - текст пояснения
                    //-     mods: ''  {string} - модификаторы блока
                    //- Вызов:
                          +field-actions('* — обязательные поля', 'some-mod')
                            p КнопкиТут
                   
                    -
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' field-actions--' + modsList[i].trim();
                        }
                      }
                   
                    .field-actions(class=allMods)&attributes(attributes)
                      if(typeof(text) !== 'undefined' && text)
                        .field-actions__text!= text
                      block
                

Форма

Название1
Название2
                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (form)
                  //- ВНИМАНИЕ: в файле две примеси
                   
                  mixin form(mods)
                   
                    //- Принимает:
                    //-   mods    {string} - список модификаторов
                    //- Вызов:
                          +form()
                            +fieldset('Название1')
                              +field-text({
                                helpText: 'Подсказка',
                                attrs: {
                                  placeholder: 'Пример'
                                }
                              })
                              +field-text({
                                helpText: 'Подсказка',
                                attrs: {
                                  placeholder: 'Пример'
                                }
                              })
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' form--' + modsList[i].trim();
                        }
                      }
                   
                    form.form(class=allMods)&attributes(attributes)
                      block
                   
                   
                   
                  mixin fieldset(legend, mods)
                   
                    //- Принимает:
                    //-   legend  {string} - название группы полей
                    //-   mods    {string} - список модификаторов
                    //- Вызов:
                          +fieldset('Название1')
                            +field-text({
                              helpText: 'Подсказка',
                              attrs: {
                                placeholder: 'Пример'
                              }
                            })
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' form--' + modsList[i].trim();
                        }
                      }
                   
                    fieldset.form__fieldset(class=allMods)&attributes(attributes)
                      legend.form__legend!= legend
                      block
                

Валидатор форм

Включается при указании на теге form атрибута data-check-form.

Для текстовых полей: по событию blur содержимое поля анализируется на соответствие регулярному выражению из атрибута data-check-pattern.

Для чекбоксов: по событию change проверяется соответствия состояния и data-check-state="on" (off).

Блок не имеет классов, упоминаемых в разметке. Чтобы взять его в сборку, упомяните form-validation в config.js#alwaysAddBlocks.

Pug «умно» обрабатывает строки, убирая обратный слеш (\), этот символ в pug нужно экранировать: не \d, а \\d.
См. пример кода ниже.

Это шутка, чекбокс можно спокойно отмечать. Или же нет.
Иначе всё — тлен!
+field-text({  title: 'Фамилия',  helpText: 'Фамилия. Не менее 2-х символов. Не обязательно.',  attrs: {    'data-check-pattern': '^[a-zа-яё]+.+'  }})+field-text({  title: 'Телефон',  helpText: 'Обязательно.',  attrs: {    type: 'tel',    require: true,    placeholder: '+7 (000) 000-00-00',    'data-check-pattern': '[\\+]?\\d?[\\s|-]?[(]?\\d{0,3}[)]?[\\s|-]?\\d{3}[\\s|-]?\\d{2}[\\s|-]?\\d{2}'  }})+field-text({  title: 'Электромыло',  helpText: 'Обязательно.',  attrs: {    type: 'email',    require: true,    'data-check-pattern': '[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?'  }})

Ссылка «вверх»

Ссылка «вверх» в нижнем правом углу страницы. Видима только если скролл больше указанного в Javascript-файле блока значения.

                  //- Pug-файл этого блока:
                  //- Все примеси в этом файле должны начинаться c имени блока (to-top)
                   
                  mixin to-top(mods)
                   
                    //- Принимает:
                    //-   mods    {string} - список модификаторов
                    //- Вызов:
                          +to-top()
                   
                    -
                      // список модификаторов
                      var allMods = '';
                      if(typeof(mods) !== 'undefined' && mods) {
                        var modsList = mods.split(',');
                        for (var i = 0; i < modsList.length; i++) {
                          allMods = allMods + ' to-top--' + modsList[i].trim();
                        }
                      }
                   
                    a.to-top#to-top(class=allMods, href='#')&attributes(attributes) ↑
                

Боковое меню страницы

Меню показывается по клику на любой элемент с data-toggle="off-canvas" или data-toggle-native="off-canvas" (в последнем случае произойдет и действие браузера по умолчанию).

//- Разметка, необходимая для использования бокового меню#off-canvas.off-canvas  aside.off-canvas__aside(role='complementary', aria-label='Боковое меню') Меню  .off-canvas__page-content Контент  .off-canvas__overlay(data-toggle='off-canvas')button.btn(type='button', data-toggle='off-canvas') Показать/скрыть боковое менюa(href='#SOME_HASH', data-toggle-native='off-canvas') Показать/скрыть боковое меню и перейти на якорь

Табы

Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.0

За словесными горами в стране, гласных и согласных живут рыбные тексты.1

Словесными горами в стране, гласных и согласных живут рыбные тексты.2

Горами в стране, гласных и согласных живут рыбные тексты.3

                //- Pug-файл этого блока:
                //- Все примеси в этом файле должны начинаться c имени блока (tabs)
                 
                mixin tabs(props, mods)
                 
                  //- Принимает:
                  //-   props        {array}
                  //-     {object}
                  //-       id       {string} - id вкладки
                  //-       text     {string} - текст на вкладке
                  //-       isActive {bool}   - флаг «это активная»
                  //-   mods         {string} - список модификаторов
                  //- Вызов:
                        +tabs([
                          {
                            'id': 'tab00',
                            'text': 'Вкладка ноль',
                            'isActive': true,
                          },
                          {
                            'id': 'tab01',
                            'text': 'Вкладка один',
                          },
                          ], 'some-mod')
                          +tabs-item('tab00', true, 'some')
                            p Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.0
                          +tabs-item('tab01')
                            p За словесными горами в стране, гласных и согласных живут рыбные тексты.1
                  -
                    // список модификаторов
                    var allMods = '';
                    if(typeof(mods) !== 'undefined' && mods) {
                      var modsList = mods.split(',');
                      for (var i = 0; i < modsList.length; i++) {
                        allMods = allMods + ' tabs--' + modsList[i].trim();
                      }
                    }
                 
                  .tabs(class=allMods)&attributes(attributes)
                    ul.tabs__links(role='tablist')
                      each tab in props
                        -
                          var isActive = (typeof(tab.isActive) !== 'undefined' && tab.isActive) ? '  tabs__link-wrap--active' : ''
                        li.tabs__link-wrap(class=isActive, role='presentation')
                          a.tabs__link(href='#'+tab.id, data-toggle='tab', role='tab')!= tab.text
                    .tabs__content-wrapper
                      block
                 
                 
                 
                mixin tabs-item(id, isActive, mods)
                 
                  //- Принимает:
                  //-   isActive {bool}   - флаг «это активная»
                  //-   mods     {string} - список модификаторов
                  //- Вызов:
                        +tabs-item('tab01', true, 'some-mod')
                          p Вкладка
                        +tabs-item('tab02', false)
                          p Вкладка
                        +tabs-item('tab03', false)
                          p Вкладка
                 
                  -
                    // список модификаторов
                    var allMods = '';
                    if(typeof(mods) !== 'undefined' && mods) {
                      var modsList = mods.split(',');
                      for (var i = 0; i < modsList.length; i++) {
                        allMods = allMods + ' tabs__content-item--' + modsList[i].trim();
                      }
                    }
                    if(typeof(isActive) !== 'undefined' && isActive)
                      allMods = allMods + '  tabs__content-item--active';
                 
                  .tabs__content-item(class=allMods, id=id, role='tabpanel')&attributes(attributes)
                    block
              

Кастомный скролл с baron

Кастомный скролл c baron. Демо кастомного скролла.

Для каждого блока нужно включать baron в blocks/baron/baron.js.

Оставлена одна тема оформления (используется по умолчанию). Стили берутся из blocks/baron/baron.scss. См. стилизацию оригинальных тем.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dicta aliquid nemo, sit possimus, eveniet tempore minus, doloremque incidunt, nihil quos aperiam ab iure quia. Ipsa sit porro incidunt, sed!

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dicta aliquid nemo, sit possimus, eveniet tempore minus, doloremque incidunt, nihil quos aperiam ab iure quia. Ipsa sit porro incidunt, sed!

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dicta aliquid nemo, sit possimus, eveniet tempore minus, doloremque incidunt, nihil quos aperiam ab iure quia. Ipsa sit porro incidunt, sed!

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dicta aliquid nemo, sit possimus, eveniet tempore minus, doloremque incidunt, nihil quos aperiam ab iure quia. Ipsa sit porro incidunt, sed!

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dicta aliquid nemo, sit possimus, eveniet tempore minus, doloremque incidunt, nihil quos aperiam ab iure quia. Ipsa sit porro incidunt, sed!

                //- Pug-файл этого блока:
                //- Блок для кастомного скролла baron: https://github.com/Diokuz/baron
                //- Нуждается в соотв. зависимости: https://www.npmjs.com/package/baron
                //- (должна быть указана в ./projectConfig.json, есть по умолчанию)
                //- ВНИМАНИЕ! Помимо вызова примеси, нужно включить baron на блоке! см. blocks/baron/baron.js
                 
                mixin baron(id, mods, tag)
                 
                  //- Принимает:
                  //-   id     {string} - ID этого конкретного блока с кастомным скроллом
                  //-   mods    {string} - список модификаторов
                  //-   tag     {string} - тег
                  //- Вызов:
                        +baron('some-mod')(style='width:100px; height: 100px')
                          p Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dicta aliquid nemo, sit possimus, eveniet tempore minus, doloremque incidunt, nihil quos aperiam ab iure quia. Ipsa sit porro incidunt, sed!
                        .some-block
                          +baron('', 'section')(class='some-block__demo')
                            p Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt dicta aliquid nemo, sit possimus, eveniet tempore minus, doloremque incidunt, nihil quos aperiam ab iure quia. Ipsa sit porro incidunt, sed!
                 
                  -
                    // список модификаторов
                    var allMods = '';
                    if(typeof(mods) !== 'undefined' && mods) {
                      var modsList = mods.split(',');
                      for (var i = 0; i < modsList.length; i++) {
                        allMods = allMods + ' baron--' + modsList[i].trim();
                      }
                    }
                    var parentTag = 'div';
                    if(typeof(tag) !== 'undefined' && tag) {
                      parentTag = tag;
                    }
                 
                  #{parentTag}.baron(id=id, class=allMods)&attributes(attributes)
                    .baron__scroller
                      block
                    .baron__track
                      //- .baron__control.baron__up ▲
                      .baron__free
                        .baron__bar
                      //- .baron__control.baron__down ▼
              

Поддержка object-fit для IE

Дополнительные стили для картинок с указанным object-fit: ...; добавится с помощью PostCSS-плагина на этапе постобработки css.

Блок не имеет классов, упоминаемых в разметке. Чтобы взять его в сборку, упомяните object-fit-polyfill в config.js#alwaysAddBlocks.

Инструменты: полифил, PostCSS-плагин, реализующий автоматическое применение полифила.

Аватар Аватар
<img src="img/demo-avatar-m.png" class="semantic-class" style="width: 128px; height: 64px;" alt="Аватар" /><img src="img/demo-avatar-f.png" class="semantic-class" style="width: 64px; height: 64px;" alt="Аватар" />
.semantic-class {  object-fit: cover;}