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

Страница

Блок страницы html class="page", благодаря которому применяются некоторые глобальные стили:

  • Смена боксовой модели на всех узлах: box-sizing: border-box; наследуется от html
  • Нормализация вьюпорта для windows-телефонов.
  • Сброс отступов для body
  • Стилевой обход 300 мс задержки touch-action: manipulation;
  • Ограничение размера картинок до 100% ширины родителя.

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

<!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>

Текст, теги

Реализуется блоком typo, все стили которого являются глобальными.

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

Заголовок 1

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

Заголовок 2

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

Заголовок 3

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

Заголовок 4

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

Заголовок 5

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

Заголовок 6

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

  • Пункт 1
    • Подпункт 1
    • Подпункт 2
  • Пункт 2
  • Пункт 3
  1. Пункт 1
    1. Подпункт 1
    2. Подпункт 2
  2. Пункт 2
  3. Пункт 3

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

Определяемая сущность 1
Некое, возможно, относительно длинное определение упомянутой сущности. Скорее всего, многострочное.
Определяемая сущность 2
Некое, возможно, относительно длинное определение. Скорее всего, длинное, весьма многострочное и многословное.
Некое, возможно, относительно длинное определение упомянутой сущности.

Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.


Параграфы, расстояние между ними. Ссылка. Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные ссылки. Грустный предупредила, дал приставка составитель решила подпоясал запятых сих ручеек которой власти до, над жизни возвращайся силуэт что не курсивных.

<a> ссылка
<strong> **действительно значимый текст**
<b> **просто выделенный текст, лид**
<i> _иностранное слово или термин_
<em> _эмфатическое ударение_
<s> информация, утратившая актуальность
<del> изменение, внесённое в документ (удаление)
<ins> изменение, внесённое в документ (добавление)
<mark> акцент маркерным выделением
<small> малозначимый текст
<abbr> АББРЕВИАТУРА
<kbd> Ctrl + C
<sup> 23
<sub> H2O
<code> `code`
Имя Фамилия
г. Лондон, ул. Виндзорский сад, д. 32 (спросить мистера Имя)
user@mail.com

Цитата. Далеко-далеко за словесными горами в стране. Далеко-далеко за словесными горами в стране.

Emmet
// Форматированный текст с символом переноса строки
// Вторая строка. Смотри так же [БЭМ-блок для кода](#code).

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

Из файлов папки sprite-svg/svg/ в папку sprite-svg/img/ будет сгенерирован файл спрайта sprite-svg.svg, который далее будет скопирован в папку сборки. Стилевой файл блока не используется. SVG-файлы будут оптимизированы перед сборкой в спрайт. Сам спрайт имеет вид:

  <svg xmlns="http://www.w3.org/2000/svg" style="display:none">
    <symbol id="icon-boo" viewBox="0 0 30 30"><path d="..."/></symbol>
    <symbol id="icon-bs" viewBox="0 0 28 28"><path d="..."/></symbol>
   ...
  </svg>

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

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

Чтобы использовать ссылки на внешние svg-файлы со спрайтами, используйте svg4everybody (включен в сборку по умолчанию).

Демонстрационный контент блока (иконки стрелок):

PNG-спрайт с spritesmith

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

Стилевой файл блока генерируется автоматически и содержит примеси для использования спрайтов. Отдельный файл элемента sprite-png__demo.scss содержит вызов примеси, генерирующей стили для всех составных частей спрайта. Пример использования части спрайта для конкретного селектора:

  .selector {
    // $temp-icon-left-arrow — $ИМЯ_ФАЙЛА_КАРТИНКИ ($ в начале)
    @include sprite($temp-icon-left-arrow);
  }

Демонстрационный контент блока (иконки стрелок):

Закрыть

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

//- Pug-файл этого блока:
//- Все примеси в этом файле должны начинаться c имени блока (close)
 
mixin close(label, mods)
 
  //- Принимает:
  //-   label {string} - описание, значение атрибута aria-label
  //- Вызов:
        +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, aria-label=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

Код

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

<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 имени блока (thumb)
 
mixin thumb(url, alt, width, height)
 
  //- Принимает:
  //-   url* {string}   - источник картинки
  //-   alt {string}    - альтернативный текст
  //-   width {string}  - соотв. атрибут тега картинки
  //-   height {string} - соотв. атрибут тега картинки
  //- Вызов:
        +thumb('img/joker.jpg', 'Джокер', 300, 200)
        +thumb('img/joker.jpg', 'Джокер', 300)
 
  - if (typeof(url) !== 'undefined')
    img.thumb(src=url, alt=alt, width=width, height=height)&attributes(attributes)
  - else
    // Не передан источник изображения

Сообщения

Обычное сообщение

Заголовок

Блок сообщения с модификаторами.

//- Pug-файл этого блока:
//- Все примеси в этом файле должны начинаться c имени блока (alert)
 
mixin alert(title, mods)
 
  //- Принимает:
  //-   title {string} - заголовок
  //-   mods {string}  - стилевые модификаторы
  //- Вызов:
        +alert()
          p Текст
        +alert('Внимание', 'warning, some-mod-name')
          p Предупреждение
          +close('Закрыть', 'sm')(class='alert__close')
        +alert('Внимание', 'danger')
          p Проблема
          +close('Закрыть', 'sm')(class='alert__close')
        +alert('Внимание', 'success')
          p Успех
          +close('Закрыть', 'sm')(class='alert__close')
 
  -
    //- список модификаторов
    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)&attributes(attributes)
    if (typeof(title) !== 'undefined' && title !== '')
      h4.alert__header!= title
    block

Лейбл

Текст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 имени блока (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(class=allMods)&attributes(attributes)
    table
      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

Пагинация

//- 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--' + modsList[i].trim();
      }
    }
    if(typeof(active) !== 'undefined' && active) {
      allMods = allMods + ' pagination--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

Круговые и секторные диаграммы

Внутренняя разметка блока (SVG) создаётся JS-ом на основании data-атрибутов (значения по умолчанию прописаны в pie-chart.js).

Если нужна секторная диаграмма, нужно указать ширину бордюра как R - 0.1 — спасибо IE (см. пример в коде примеси).

30%64%
//- Pug-файл этого блока:
//- Все примеси в этом файле должны начинаться c имени блока (pie-chart)
 
mixin pie-chart(percent, mods)
 
  //- Принимает:
  //-   percent  {string} - процент заполнения
  //-   mods     {string} - список модификаторов
  //- Вызов:
        +pie-chart('30', 'success')
        +pie-chart('30')(data-size='200' data-border='10')
        +pie-chart('99', 'radial')(data-size='120' data-border='59.9')
  -
    // список модификаторов
    var allMods = '';
    if(typeof(mods) !== 'undefined' && mods) {
      var modsList = mods.split(',');
      for (var i = 0; i < modsList.length; i++) {
        allMods = allMods + ' pie-chart--' + modsList[i].trim();
      }
    }
    if(typeof(attributes['aria-valuemin']) === 'undefined') {
      attributes['aria-valuemin'] = 0;
    }
    if(typeof(attributes['aria-valuemax']) === 'undefined') {
      attributes['aria-valuemax'] = 100;
    }
 
  span.pie-chart(role='progressbar', class=allMods, aria-valuenow=percent)&attributes(attributes)= percent + '%'

Комментарий

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

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

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

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

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

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

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

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

//- 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: '

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

',
mods: 'admin', }) +comment({ username: 'Докер', content: '

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

',
})   - // список модификаторов 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

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

По умолчанию предназначен для встраивания роликов 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 имени блока (tooltip)
 
mixin tooltip(text, mods)
 
  //- Принимает:
  //-   text    {string} - текст
  //-   mods    {string} - список модификаторов
  //- Вызов:
        +tooltip('Текст подсказки')
        p Текст и подсказка: #[+tooltip('внутри можно было использовать разметку')]
 
  -
    // список модификаторов
    var allMods = '';
    if(typeof(mods) !== 'undefined' && mods) {
      var modsList = mods.split(',');
      for (var i = 0; i < modsList.length; i++) {
        allMods = allMods + ' tooltip--' + modsList[i].trim();
      }
    }
 
  span.tooltip(class=allMods)&attributes(attributes)
    button.tooltip__btn(type='button', aria-label='more info', data-tooltip-content!=text) Подсказка

Кнопка

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

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

//- 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. Стилизация ошибочного состояния вынесена в отдельный файл.

//- 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

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

В стилевом файле есть закомментированные фрагменты для замены нативного элемента своим (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

Селекты

Название селекта
Подсказка
Название селекта
Подсказка
//- 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
    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

Группа полей

//- Pug-файл этого блока:
//- Все примеси в этом файле должны начинаться c имени блока (fields-group)
 
mixin fields-group(mods)
 
  //- Принимает:
  //-   mods    {string} - список модификаторов
  //- Вызов:
        +fields-group()
          +field-text({
            helpText: 'Подсказка',
            attrs: {
              placeholder: 'Логин'
            }
          })
          +field-text({
            attrs: {
              type: 'password',
              placeholder: 'Пароль'
            },
          })
          +field-actions()
            +btn('Отправить', 'primary')
 
  -
    // список модификаторов
    var allMods = '';
    if(typeof(mods) !== 'undefined' && mods) {
      var modsList = mods.split(',');
      for (var i = 0; i < modsList.length; i++) {
        allMods = allMods + ' fields-group--' + modsList[i].trim();
      }
    }
 
  .fields-group(class=allMods)&attributes(attributes)
    block

Форма

Название1
Название2
//- Pug-файл этого блока:
//- Все примеси в этом файле должны начинаться c имени блока (form)
//- ВНИМАНИЕ: в файле две примеси
 
mixin form(mods)
 
  //- Принимает:
  //-   mods    {string} - список модификаторов
  //- Вызов:
        +form('mod')
 
  -
    // список модификаторов
    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} - список модификаторов
  //- Вызов:
        +form('mod')
 
  -
    // список модификаторов
    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

Определение мобильного устройства

JavaScript, добавляющий на <html> классы is-mobile, если страница открыта с мобильного устройства (см. в devtools с эмуляцией). Должен быть вставлен в <head>.

Зависит от isMobile. Последний должен быть включен в сборку (есть по умолчанию) или подключен к странице иным образом.

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

Ссылка «вверх» в нижнем правом углу страницы. Видима только если скролл больше указанного в 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) ↑

Карусель с swipe

ВНИМАНИЕ: примесь возвращает только разметку. Нужно включить и настроить карусель в swipe/swipe.js

слайд1
слайд2
слайд3
слайд4
слайд5
слайд6
слайд7
слайд8
//- Pug-файл этого блока:
//- Все примеси в этом файле должны начинаться c имени блока (swipe)
//- ВНИМАНИЕ! Примесь возвращает только разметку.
//- Не забудьте включить и настроить карусель в swipe/swipe.js
 
mixin swipe(id, mods)
 
  //- Принимает:
  //-   id      {string} - идентификатор
  //-   mods    {string} - список модификаторов
  //- Вызов:
        +swipe('swipe-demo')
          div слайд1
          div слайд2
          div слайд3
          div слайд4
          div слайд5
          div слайд6
          div слайд7
          div слайд8
 
  -
    // список модификаторов
    var allMods = '';
    if(typeof(mods) !== 'undefined' && mods) {
      var modsList = mods.split(',');
      for (var i = 0; i < modsList.length; i++) {
        allMods = allMods + ' swipe--' + modsList[i].trim();
      }
    }
 
  .swipe(id=id, class=allMods)&attributes(attributes)
    .swipe-wrap
      block

Выбор диапазона с noUiSlider

ВНИМАНИЕ: примесь возвращает только разметку. Нужно включить и настроить слайдер в nouislider/nouislider.js

//- Pug-файл этого блока:
//- Все примеси в этом файле должны начинаться c имени блока (nouislider)
//- ВНИМАНИЕ! Примесь возвращает только разметку.
//- Не забудьте включить и настроить слайдер в nouislider/nouislider.js
 
mixin nouislider(id, mods)
 
  //- Принимает:
  //-   id      {string} - идентификатор
  //-   mods    {string} - список модификаторов
  //- Вызов:
        +nouislider('demo-nouislider')
          input#demo-nouislider-start(type='number', value='10')
          input#demo-nouislider-end(type='number', value='90')
 
  -
    // список модификаторов
    var allMods = '';
    if(typeof(mods) !== 'undefined' && mods) {
      var modsList = mods.split(',');
      for (var i = 0; i < modsList.length; i++) {
        allMods = allMods + ' nouislider--' + modsList[i].trim();
      }
    }
 
  .nouislider(id=id, class=allMods)&attributes(attributes)
  block

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

Меню показывается по клику на любой элемент с 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