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

Страница

Блок страницы 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).

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

По умолчанию в сборку берётся файл с примесями для создания модульной сетки: ./src/scss/mixins/grid-mixins.scss. Отдельного БЭМ-блока для сеток нет, используйте семантические классы и применяйте к ним примеси. <br> Пример использования на 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.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
  //-   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, 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

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

Разделитель «или» с горизонтальными линиями.

или
Текст взамен «или»
//- 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

Код

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

<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', 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
Текст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()
          +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

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

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

Кастомный скролл с 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 ▼