Commit 0fbddb05 authored by Nikolay Gromov's avatar Nikolay Gromov

Допилил слежение за блоками

parent 5373a9d2
......@@ -3,13 +3,13 @@ build/*
!build/readme.md
src/pug/mixins.pug
src/js/entry.js
src/js/blocks-lib.js
src/scss/style.scss
src/scss/blocks-lib.scss
src/blocks/sprite-svg/img/sprite.svg
src/blocks/sprite-png/sprite-png.scss
src/blocks/sprite-png/img/sprite-*.png
faviconData.json
__MACOSX
.Saved/
_arc/
......
......@@ -34,7 +34,7 @@ let config =
"./script.js"
],
"addAssets": {
"./src/img/avatar-*": "img/",
"./src/img/demo-avatar-*": "img/",
"./src/img/DSC_*": "img/",
"./src/fonts/demo-empty-open-sans.woff2": "fonts/",
"./src/favicon/*.{png,ico,svg,xml,webmanifest}": "img/favicon"
......
......@@ -261,6 +261,70 @@ function generatePngSprite(cb) {
exports.generatePngSprite = generatePngSprite;
function writeBlocksLibSass(cb) {
let allBlocksWithStyleFiles = getDirectories(dir.blocks, 'scss');
let styleImports = '';
config.addStyleBefore.forEach(function(src) {
styleImports += `@import "${src}";\n`;
});
allBlocksWithStyleFiles.forEach(function(block) {
let src = `${dir.blocks}${block}/${block}.scss`;
styleImports += `@import "${src}";\n`;
});
config.addStyleAfter.forEach(function(src) {
styleImports += `@import "${src}";\n`;
});
fs.writeFileSync(`${dir.src}scss/blocks-lib.scss`, styleImports);
cb();
}
exports.writeBlocksLibSass = writeBlocksLibSass;
function writeBlocksLibJs(cb) {
let allBlocksWithJsFiles = getDirectories(dir.blocks, 'js');
let jsRequires = '';
config.addJsBefore.forEach(function(src) {
jsRequires += `require('${src}');\n`;
});
allBlocksWithJsFiles.forEach(function(block) {
jsRequires += `require('../blocks/${block}/${block}.js');\n`;
});
config.addJsAfter.forEach(function(src) {
jsRequires += `require('${src}');\n`;
});
fs.writeFileSync(`${dir.src}js/blocks-lib.js`, jsRequires);
cb();
}
exports.writeBlocksLibJs = writeBlocksLibJs;
function compileBlocksLibSass() {
return src(`${dir.src}scss/blocks-lib.scss`, { sourcemaps: true })
.pipe(plumber())
.pipe(debug({title: 'Compiles:'}))
.pipe(sass({includePaths: [__dirname+'/']}))
.pipe(postcss(postCssPlugins))
.pipe(dest(`${dir.build}/css`, { sourcemaps: '.' }))
.pipe(browserSync.stream());
}
exports.compileBlocksLibSass = compileBlocksLibSass;
function buildBlocksLibJs() {
return browserify({
entries: dir.src + '/js/blocks-lib.js',
debug: true
})
.transform('babelify', {presets: ['@babel/preset-env',]})
.bundle()
.pipe(source('blocks-lib.js'))
.pipe(buffer())
.pipe(gulpIf(!isDev, uglify()))
.pipe(dest(dir.build + '/js'));
}
exports.buildBlocksLibJs = buildBlocksLibJs;
function clearBuildDir() {
return del([
`${dir.build}**/*`,
......@@ -306,14 +370,14 @@ function serve() {
));
watch([`${dir.blocks}**/*.pug`], { events: ['unlink'], delay: 100 }, series(writePugMixinsFile));
watch([`${dir.src}pug/**/*.pug`, `!${dir.src}pug/mixins.pug`], { delay: 100 }, series(
compilePugFast,
compilePug,
parallel(writeSassImportsFile, writeJsRequiresFile),
parallel(compileSass, buildJs),
reload,
));
watch([`${dir.blocks}**/*.scss`], { events: ['all'], delay: 100 }, series(writeSassImportsFile, compileSass));
watch([`${dir.src}scss/**/*.scss`, `!${dir.src}scss/style.scss`], { events: ['all'], delay: 100 }, series(compileSass));
watch([`${dir.src}js/**/*.js`, `!${dir.src}js/entry.js`, `${dir.blocks}**/*.js`], { events: ['all'], delay: 100 }, series(writeJsRequiresFile, buildJs, reload));
watch([`${dir.blocks}**/*.scss`], { events: ['all'], delay: 100 }, series(writeSassImportsFile, writeBlocksLibSass, compileSass, compileBlocksLibSass));
watch([`${dir.src}scss/**/*.scss`, `!${dir.src}scss/style.scss`, `!${dir.src}scss/blocks-lib.scss`], { events: ['all'], delay: 100 }, series(compileSass, compileBlocksLibSass));
watch([`${dir.src}js/**/*.js`, `!${dir.src}js/entry.js`, `!${dir.src}js/blocks-lib.js`, `${dir.blocks}**/*.js`], { events: ['all'], delay: 100 }, series(writeJsRequiresFile, writeBlocksLibJs, buildJs, buildBlocksLibJs, reload));
watch([`${dir.blocks}**/img/*.{jpg,jpeg,png,gif,svg,webp}`], { events: ['all'], delay: 100 }, series(copyImg, reload));
watch([`${dir.blocks}sprite-svg/svg/*.svg`], { events: ['all'], delay: 100 }, series(generateSvgSprite, copyImg));
watch([`${dir.blocks}sprite-png/png/*.png`], { events: ['all'], delay: 100 }, series(generatePngSprite, copyImg, compileSass));
......@@ -325,8 +389,8 @@ exports.default = series(
parallel(compilePugFast, copyAssets),
parallel(generateSvgSprite, generatePngSprite),
parallel(copyImg),
parallel(writeSassImportsFile, writeJsRequiresFile),
parallel(compileSass, buildJs),
parallel(writeSassImportsFile, writeJsRequiresFile, writeBlocksLibSass, writeBlocksLibJs),
parallel(compileSass, compileBlocksLibSass, buildJs, buildBlocksLibJs),
serve,
);
......
......@@ -60,7 +60,8 @@
"tabs": [],
"object-fit-polyfill": [],
"or": [],
"baron": []
"baron": [],
"blocks-library": []
},
"addCssBefore": [
"./src/scss/functions.scss",
......
......@@ -49,7 +49,7 @@ $border-radius: rem(3px) !default;
}
&__close {
position: absolute;
position: absolute !important;
top: 0;
right: 0;
margin: 0;
......
var baron = require('baron');
document.addEventListener('DOMContentLoaded', function(){
baron({
......
@import './src/scss/variables.scss';
@import './src/scss/mixins.scss';
// В этом файле должны быть стили для БЭМ-блока blocks-library, его элементов,
// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...
// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority
.blocks-library {
$block-name: &; // #{$block-name}__element
&__title {
font-weight: 400;
}
......@@ -119,14 +122,14 @@
}
&__menu-toggler {
position: fixed;
position: fixed !important;
backface-visibility: hidden;
bottom: 0;
left: 0;
background-color: #000;
width: 40px;
background-color: #000 !important;
width: 40px !important;
height: 40px;
padding: 5px;
padding: 5px !important;
.off-canvas--open & {
display: none;
......@@ -135,8 +138,7 @@
& > span,
& > span:before,
& > span:after {
background-color: #fff;
background-color: #fff !important;
}
}
}
Оформление одного блока при описании в библиотеке блоков.
......@@ -29,5 +29,11 @@ $border-radius: rem(3px) !default;
white-space: pre;
background-color: transparent;
min-height: 1em;
p,
div {
display: inline-block;
margin: 0;
}
}
}
// Факт открытия
$('#drop-demo-01').closest('.dropdown').on('shown.nth.dropdown', function () {
console.log('Дроп с id="drop-demo-01": сработало событие shown.nth.dropdown');
});
// Факт закрытия
$('#drop-demo-01').closest('.dropdown').on('hidden.nth.dropdown', function () {
console.log('Дроп с id="drop-demo-01": сработало событие hidden.nth.dropdown');
});
/* ========================================================================
* Основано на: Bootstrap dropdown.js v3.3.6
* Все изменения сопровождены закомментироваными оригиналами
* ======================================================================== */
+function ($) {
'use strict';
// DROPDOWN CLASS DEFINITION
// =========================
var backdrop = '.dropdown-backdrop'
var toggle = '[data-toggle="dropdown"]'
var Dropdown = function (element) {
// $(element).on('click.bs.dropdown', this.toggle)
$(element).on('click.nth.dropdown', this.toggle)
}
// Dropdown.VERSION = '3.3.6'
function getParent($this) {
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
// selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = selector && $(selector)
return $parent && $parent.length ? $parent : $this.parent()
}
function clearMenus(e) {
if (e && e.which === 3) return
$(backdrop).remove()
$(toggle).each(function () {
var $this = $(this)
var $parent = getParent($this)
var relatedTarget = { relatedTarget: this }
// if (!$parent.hasClass('open')) return
if (!$parent.hasClass('dropdown--open')) return
if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
// Выходим, если клик пришелся на элемент внутри .dropdown__menu
if (e && e.type == 'click' && /dropdown__menu/i.test(e.toElement.offsetParent.className)) return
// $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
// $parent.trigger(e = $.Event('hide.nth.dropdown', relatedTarget))
// if (e.isDefaultPrevented()) return
$this.attr('aria-expanded', 'false')
// $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
$parent.removeClass('dropdown--open').trigger($.Event('hidden.nth.dropdown', relatedTarget))
})
}
Dropdown.prototype.toggle = function (e) {
var $this = $(this)
// if ($this.is('.disabled, :disabled')) return
if ($this.is(':disabled')) return
var $parent = getParent($this)
// var isActive = $parent.hasClass('open')
var isActive = $parent.hasClass('dropdown--open')
clearMenus()
if (!isActive) {
// if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
if ('ontouchstart' in document.documentElement) {
// if mobile we use a backdrop because click events don't delegate
$(document.createElement('div'))
.addClass('dropdown-backdrop')
.insertAfter($(this))
.on('click', clearMenus)
}
var relatedTarget = { relatedTarget: this }
// $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
// $parent.trigger(e = $.Event('show.nth.dropdown', relatedTarget))
// if (e.isDefaultPrevented()) return
$this
.trigger('focus')
.attr('aria-expanded', 'true')
$parent
// .toggleClass('open')
.toggleClass('dropdown--open')
// .trigger($.Event('shown.bs.dropdown', relatedTarget))
.trigger($.Event('shown.nth.dropdown', relatedTarget))
}
return false
}
Dropdown.prototype.keydown = function (e) {
if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
var $this = $(this)
e.preventDefault()
e.stopPropagation()
// if ($this.is('.disabled, :disabled')) return
if ($this.is(':disabled')) return
var $parent = getParent($this)
// var isActive = $parent.hasClass('open')
var isActive = $parent.hasClass('dropdown--open')
if (!isActive && e.which != 27 || isActive && e.which == 27) {
if (e.which == 27) $parent.find(toggle).trigger('focus')
return $this.trigger('click')
}
// var desc = ' li:not(.disabled):visible a'
// var $items = $parent.find('.dropdown-menu' + desc)
var $items = $parent.find('.dropdown__menu a')
if (!$items.length) return
var index = $items.index(e.target)
if (e.which == 38 && index > 0) index-- // up
if (e.which == 40 && index < $items.length - 1) index++ // down
if (!~index) index = 0
$items.eq(index).trigger('focus')
}
// DROPDOWN PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
// var data = $this.data('bs.dropdown')
var data = $this.data('nth.dropdown')
// if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
if (!data) $this.data('nth.dropdown', (data = new Dropdown(this)))
if (typeof option == 'string') data[option].call($this)
})
}
var old = $.fn.dropdown
$.fn.dropdown = Plugin
$.fn.dropdown.Constructor = Dropdown
// DROPDOWN NO CONFLICT
// ====================
$.fn.dropdown.noConflict = function () {
$.fn.dropdown = old
return this
}
// APPLY TO STANDARD DROPDOWN ELEMENTS
// ===================================
$(document)
// .on('click.bs.dropdown.data-api', clearMenus)
// .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
// .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
// .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
// .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
.on('click.nth.dropdown.data-api', clearMenus)
.on('click.nth.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.nth.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.nth.dropdown.data-api', toggle, Dropdown.prototype.keydown)
.on('keydown.nth.dropdown.data-api', '.dropdown__menu', Dropdown.prototype.keydown)
}(jQuery);
//- Все примеси в этом файле должны начинаться c имени блока (dropdown)
mixin dropdown(text, id, mods)
//- Принимает:
//- text {string} - текст кнопки
//- id* {string} - идентификатор
//- mods {string} - список модификаторов
//- Вызов:
+dropdown('Дроп', 'drop-01')
p текст
+dropdown('выпадающее меню', 'drop-02', 'up, right')
.menu
span.menu__item
a.menu__link(href='') Пункт списка
span.menu__item
a.menu__link(href='') Пункт меню весьма длинный
span.menu__item
a.menu__link(href='') Второй пункт
-
// список модификаторов
var allMods = '';
if(typeof(mods) !== 'undefined' && mods) {
var modsList = mods.split(',');
for (var i = 0; i < modsList.length; i++) {
allMods = allMods + ' dropdown--' + modsList[i].trim();
}
}
if(typeof(id) !== 'undefined' && id)
span.dropdown(class=allMods)&attributes(attributes)
button.btn.dropdown__toggler(id=id, type='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')!= text
span.dropdown__menu(aria-labelledby=id)
block
else
span Укажите уникальный #[code id] этого выпадающего элемента
// В этом файле должны быть стили для БЭМ-блока dropdown, его элементов,
// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...
// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority
$text-color: hsl(0, 0%, 10%) !default;
$border-color: hsl(0, 0%, 60%) !default;
$border-radius: rem(3px) !default;
$transition-time: 0.3s !default;
.dropdown {
$block-name: &; // #{$block-name}__element
position: relative;
display: inline-block;
&__menu {
position: absolute;
z-index: -1;
top: 100%;
left: 0;
max-width: 90vw;
width: 1px;
margin: 0;
background-color: #fff;
color: $text-color;
opacity: 0;
visibility: hidden;
overflow: hidden;
transition: opacity $transition-time;
}
&--open {
#{$block-name}__menu {
z-index: 1;
visibility: visible;
opacity: 1;
width: auto;
}
}
&--up {
#{$block-name}__menu {
top: auto;
bottom: 100%;
}
}
&--right {
#{$block-name}__menu {
left: auto;
right: 0;
}
}
}
Основан на dropdown.js из Bootstrap. Изменения минимальны.
<p class="alert alert--warning">Зависит от <a href="https://jquery.com/">jQuery</a> (включен в сборку по умолчанию).</p>
document.addEventListener('DOMContentLoaded', function(){
if (window.isMobile !== undefined) {
// console.log(isMobile);
if(isMobile.any) {
var rootClasses = ' is-mobile';
for (key in isMobile) {
if(typeof isMobile[key] === 'boolean' && isMobile[key] && key !== 'any') rootClasses += ' is-mobile--'+key;
if(typeof isMobile[key] === 'object' && key !== 'other') {
for (type in isMobile[key]) {
if(isMobile[key][type]) rootClasses += ' is-mobile--'+key+'-'+type;
}
}
}
document.documentElement.className += rootClasses;
}
}
else {
console.log('Классы для мобильных не добавлены: в сборке отсутствует isMobile.js');
}
});
// В этом файле должны быть стили для БЭМ-блока is-mobile, его элементов,
// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...
// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority
.is-mobile {
&--android-device {}
&--apple-device {}
&--amazon-device {}
&--windows-device {}
&--phone {}
&--tablet {}
&--seven_inch {}
}
JavaScript, добавляющий на `<html>` классы `is-mobile`, если страница открыта с мобильного устройства (см. в devtools с эмуляцией). Должен быть вставлен в `<head>`.
Зависит от [isMobile](https://github.com/kaimallea/isMobile). Последний должен быть включен в сборку (есть по умолчанию) или подключен к странице иным образом.
По умолчанию данные меню берутся из `main-nav/main-nav.json` и передаются в компилятор pug (см. `gulpfile.js`).
По получению ссылками фокуса на их родителей с `.main-nav__item` добавляется модификатор `.main-nav__item--show-child`, что позволяет работать со вложенными меню с клавиатуры (предусмотрено 3 уровня).
Пункты меню берутся из `main-nav/main-nav.data.json`.
На малых ширинах преобразуется в мобильный вид, скрывается/показывается по клику на бургер, если JS включен (на `html` есть класс `js`).
var $ = require('jquery');
// Демо событий модальных окон
$(document).ready(function(){
$('#modal-demo-01').on('show.nth.modal', function(){
......@@ -383,4 +385,4 @@ $(document).ready(function(){
Plugin.call($target, option, this)
})
}(jQuery);
}($);
document.addEventListener('DOMContentLoaded', function(){
if(document.getElementById('demo-nouislider')) {
var demoNoUiSlider = document.getElementById('demo-nouislider');
var demoNoUiSliderStartInput = document.getElementById('demo-nouislider-start');
var demoNoUiSliderEndInput = document.getElementById('demo-nouislider-end');
noUiSlider.create(demoNoUiSlider, {
start: [demoNoUiSliderStartInput.value, demoNoUiSliderEndInput.value],
connect: true,
step: 1,
range: {
'min': 0,
'max': 100
}
});
demoNoUiSlider.noUiSlider.on('update', function( values, handle ) {
var value = values[handle];
if ( handle ) {
demoNoUiSliderEndInput.value = Math.round(value);
} else {
demoNoUiSliderStartInput.value = Math.round(value);
}
});
demoNoUiSliderEndInput.addEventListener('change', function(){
demoNoUiSlider.noUiSlider.set([null, this.value]);
});
demoNoUiSliderStartInput.addEventListener('change', function(){
demoNoUiSlider.noUiSlider.set([this.value, null]);
});
}
});
//- Все примеси в этом файле должны начинаться 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
// В этом файле должны быть стили для БЭМ-блока nouislider, его элементов,
// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...
// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority
.nouislider {
// По умолчанию в сборку берется стилевой файл этого блока, предоставляемый
// автором пакета (см. файл настройки проекта, там подключается
// node_modules/nouislider/distribute/nouislider.css).
// Надо стилизовать — копипастить из исходника и убирать исходник из сборки.
}
ВНИМАНИЕ: примесь возвращает только разметку. Нужно включить и настроить слайдер в `nouislider/nouislider.js`
var objectFitImages = require('object-fit-images');
document.addEventListener('DOMContentLoaded', function(){
objectFitImages();
});
......@@ -39,7 +39,8 @@ $off-canvas-width: 250px !default; // ширина этого бло
color: #fff;
&:hover,
&:focus {
&:focus,
&:visited {
color: #fff;
background-color: transparent;
}
......
Разделитель «или» с горизонтальными линиями.
$(document).ready(function(){
$("#promo").owlCarousel({
items: 3,
nav: true,
loop: true,
center: true,
responsive : {
0 : {
items: 1,
nav: true,
loop: true,
center: true,
},
480 : {
items: 3,
},
768 : {
items: 3,
},
992 : {
items: 3,
},
1200 : {
items: 3,
},
1800 : {
items: 3,
}
}
});
});
//- Все примеси в этом файле должны начинаться c имени блока (owl-carousel)
//- ВНИМАНИЕ! Примесь возвращает только разметку.
//- Не забудьте включить и настроить карусель в owl-carousel/owl-carousel.js
mixin owl-carousel(id, mods)
//- Принимает:
//- id {string} - идентификатор
//- mods {string} - список модификаторов
//- Вызов:
+owl-carousel('promo')
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 + ' owl-carousel--' + modsList[i].trim();
}
}
.owl-carousel(id=id, class=allMods)&attributes(attributes)
block
// В этом файле должны быть стили для БЭМ-блока owl-carousel, его элементов,
// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...
// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority
.owl-carousel {
// По умолчанию в сборку берется стилевой файл этого блока, предоставляемый
// автором пакета (см. файл настройки проекта, там подключается
// node_modules/owl.carousel/dist/assets/owl.carousel.css).
// Надо стилизовать — копипастить из исходника и убирать исходник из сборки.
}
ВНИМАНИЕ: примесь возвращает только разметку. Нужно включить и настроить карусель в `owl-carousel/owl-carousel.js`
<p class="alert alert--warning">Зависит от <a href="https://jquery.com/">jQuery</a> (включен в сборку по умолчанию).</p>
«Подвал» страницы.
Обертка и внутренняя обертка блока.
Обертка и внутренняя обертка «подвала» страницы.
«Шапка» страницы.
Обертка и внутренняя обертка блока.
Обертка и внутренняя обертка «шапки» страницы.
Блок страницы `html class="page"`, благодаря которому применяются некоторые глобальные стили:
- Смена боксовой модели на всех узлах: `box-sizing: border-box;` наследуется от `html`
- Нормализация вьюпорта для windows-телефонов.
- Сброс отступов для `body`
- Стилевой обход 300 мс задержки `touch-action: manipulation;`
- Ограничение размера картинок до 100% ширины родителя.
Блок страницы `html class="page"`. Содержит стили `.page`, некоторые глобальные стили и типографику:
В стилизацию блока включена стилизация «прибитого подвала».
document.addEventListener('DOMContentLoaded', function(){
function $$(selector, context) {
context = context || document;
var elements = context.querySelectorAll(selector);
return Array.prototype.slice.call(elements);
}
var charts = $$('.pie-chart');
var options = {
size: 100,
border: 20,
}
for (var i = 0; i < charts.length; i++) {
var size = charts[i].getAttribute('data-size') || options.size;
var border = charts[i].getAttribute('data-border') || options.border;
var radius = (size / 2) - (border / 2);
var fullStroke = 2 * 3.141592 * radius;
var percentText = parseFloat(charts[i].textContent);
var percent = fullStroke / 100 * percentText;
var nameSpace = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(nameSpace, 'svg');
var circle = document.createElementNS(nameSpace, 'circle');
var circleBack = document.createElementNS(nameSpace, 'circle');
var title = document.createElementNS(nameSpace, 'title');
var span = document.createElement('span');
span.className = 'pie-chart__descr';
span.innerHTML = charts[i].textContent;
svg.setAttribute('class', 'pie-chart__svg');
svg.setAttribute('viewBox', '0 0 ' + size + ' ' + size);
svg.setAttribute('width', size);
svg.setAttribute('height', size);
circleBack.setAttribute('r', (size / 2));
circleBack.setAttribute('class', 'pie-chart__circle-back');
circleBack.setAttribute('cx', size / 2);
circleBack.setAttribute('cy', size / 2);
circle.setAttribute('class', 'pie-chart__circle');
circle.setAttribute('r', radius);
circle.setAttribute('cx', size / 2);
circle.setAttribute('cy', size / 2);
circle.setAttribute('stroke-dasharray', percent + ' ' + fullStroke);
circle.setAttribute('stroke-width', border);
title.textContent = charts[i].textContent;
charts[i].textContent = '';
svg.appendChild(title);
svg.appendChild(circleBack);
svg.appendChild(circle);
charts[i].appendChild(svg);
charts[i].appendChild(span);
}
});
//- Все примеси в этом файле должны начинаться 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 + '%'
// В этом файле должны быть стили для БЭМ-блока pie-chart, его элементов,
// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...
// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority
$text-color: hsl(0, 0%, 10%) !default;
$font-size: 1rem !default;
$gray-light: hsl(0, 0%, 60%) !default;
$gray-lighter: hsl(0, 0%, 80%) !default;
.pie-chart {
$block-name: &; // #{$block-name}__element
.js & {
display: inline-block;
position: relative;
min-width: 100px; // соответствуют ширине по умолчанию (указана в pie-chart.js)
min-height: 100px; // соответствуют ширине по умолчанию (указана в pie-chart.js)
&__svg {
display: block;
transform: rotate(-90deg);
}
&__circle-back {
fill: $gray-lighter;
}
&__circle {
fill: $gray-lighter;
stroke: $gray-light;
}
&__descr {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
Внутренняя разметка блока (SVG) создаётся JS-ом на основании `data`-атрибутов (значения по умолчанию прописаны в `pie-chart.js`).
Если нужна секторная диаграмма, нужно указать ширину бордюра как `R - 0.1` — спасибо IE (см. пример в коде примеси).
......@@ -24,6 +24,7 @@ $transition-time: 0.3s !default;
border-radius: $border-radius;
max-width: 100%;
min-height: 1px;
white-space: nowrap;
transition: width $transition-time;
}
......
Из файлов папки `sprite-png/png/` в папку `sprite-png/img/` будет сгенерирован файл спрайта `sprite-ЧИСЛОВОЙ_ИНДЕКС.svg`, который далее будет скопирован в папку сборки.
Из файлов `sprite-png/png/` будет сгенерирован файл спрайта `sprite-png/img/sprite-ЧИСЛОВОЙ_ИНДЕКС.svg`, который будет скопирован в папку сборки.
**Стилевой файл блока генерируется автоматически** и содержит примеси для использования спрайтов.
Пример использования части спрайта для конкретного селектора:
Пример использования для конкретного селектора:
<pre class="code">
<code>.selector {</code>
......@@ -10,8 +10,3 @@
<code> @include sprite($temp-icon-left-arrow);</code>
<code>}</code>
</pre>
Демонстрационный контент блока (иконки стрелок):
<div class="temp-icon-right-arrow" style="display: inline-block;"></div>
<div class="temp-icon-left-arrow" style="display: inline-block;"></div>
Из файлов папки `sprite-svg/svg/` в папку `sprite-svg/img/` будет сгенерирован файл спрайта `sprite.svg`, который далее будет скопирован в папку сборки. Стилевой файл блока не используется. SVG-файлы будут оптимизированы перед сборкой в спрайт. Сам спрайт имеет вид:
Из файлов `sprite-svg/svg/` будет сгенерирован файл спрайта `sprite-svg/img/sprite.svg`, который будет скопирован в папку сборки. Стилевой файл блока не используется. SVG-файлы будут оптимизированы перед сборкой в спрайт. Сам спрайт имеет вид:
<pre class="code">
<code>&lt;svg xmlns="http://www.w3.org/2000/svg"&gt;</code>
......@@ -8,7 +8,7 @@
<code>&lt;/svg&gt;</code>
</pre>
Для вставки на страницу используйте конструкции <code>svg &gt; use</code> со ссылками на <code>id</code> символа:
Для вставки на страницу используйте <code>svg &gt; use</code> со ссылками на <code>id</code> символа:
<pre class="code">
<code>svg(width="32", height="32")</code>
......
ВНИМАНИЕ: примесь возвращает только разметку. Нужно включить и настроить карусель в `swipe/swipe.js`
document.addEventListener('DOMContentLoaded', function(){
if(document.getElementById('swipe-demo')) {
window.mySwipe = new Swipe(document.getElementById('swipe-demo'), {
startSlide: 0,
speed: 400,
auto: 3000,
draggable: true,
continuous: true,
disableScroll: true,
stopPropagation: true,
callback: function(index, elem, dir) {},
transitionEnd: function(index, elem) {}
});
// включить видимость блока (по умолчанию скрыт)
document.getElementById('swipe-demo').classList.add('swipe--enable');
}
});
//- Все примеси в этом файле должны начинаться 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
// В этом файле должны быть стили для БЭМ-блока swipe, его элементов,
// модификаторов, псевдоселекторов, псевдоэлементов, @media-условий...
// Очередность: http://nicothin.github.io/idiomatic-pre-CSS/#priority
.swipe {
$block-name: &; // #{$block-name}__element
overflow: hidden;
position: relative;
visibility: hidden;
}
.swipe-wrap {
overflow: hidden;
position: relative;
& > div {
float: left;
width: 100%;
position: relative;
overflow: hidden;
}
}
......@@ -68,7 +68,7 @@ $screen-xxl: 1800px !default;
border-bottom: 0;
&:not(:last-child) { // stylelint-disable-line max-nesting-depth
margin-bottom: $line-height;
margin-bottom: 1em * $line-height;
}
}
......
extends ../pug/layout-off-canvas.pug
extends ../pug/layout-block-lib.pug
block meta
title Библиотека
meta(name='description', content='')
block append head
link(rel='stylesheet', href='css/blocks-library.css')
link(rel='stylesheet', href='css/blocks-lib.css')
style.
.components-demo {
display: block;
......@@ -108,12 +108,10 @@ block content
code &lt;/body>
code &lt;/html>
//- +block-lib('typo', 'Текст, теги', false)
//- include:markdown-it(html='true') ../blocks/typo/readme.md
+block-lib('grid-mixins', 'Примеси-генераторы модульной сетки', false, 'grid')
:markdown-it()
По умолчанию в сборку берётся файл с примесями для создания модульной сетки: `./src/scss/mixins/grid-mixins.scss`. Отдельного БЭМ-блока для сеток нет, используйте семантические классы и применяйте к ним примеси. <br>
В сборку берётся `./src/scss/mixins/grid-mixins.scss` с примесями-генераторами. Отдельного БЭМ-блока для сеток нет, используйте семантические классы и применяйте к ним примеси.
[Пример использования на codepen.io](https://codepen.io/nicothin/pen/aJEOwE?editors=1100).
Необходимая структура:
......@@ -216,7 +214,7 @@ block content
+block-lib('thumb', 'Картинки-миниатюры', false)
include:markdown-it(html='true') ../blocks/thumb/readme.md
+thumb('img/joker.jpg', 'Джокер', 300, 200)
+thumb('img/demo-avatar-m.png', 'User', 150, 150)
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/thumb/thumb.pug
......@@ -339,32 +337,28 @@ block content
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/progress/progress.pug
+block-lib('pie-chart', 'Круговые и секторные диаграммы', false)
include:markdown-it(html='true') ../blocks/pie-chart/readme.md
+pie-chart('30')
+pie-chart('64')(data-size='120', data-border='59.9')
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/pie-chart/pie-chart.pug
+block-lib('comment', 'Комментарий', false)
include:markdown-it(html='true') ../blocks/comment/readme.md
+comment({
username: 'Джокер',
avatarURL: 'img/joker.jpg',
avatarURL: 'img/demo-avatar-m.png',
authorURL: '/users/joker',
content: '<p>Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.</p>',
mods: 'admin',
})
+comment({
username: 'Джокер',
username: 'Джокересса',
avatarURL: 'img/demo-avatar-f.png',
content: '<p>Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.</p>',
})
+comment({
username: 'Джокер',
username: 'Джокер 2',
avatarURL: 'img/demo-avatar-m.png',
content: '<p>Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.</p>',
})
+comment({
username: 'Джокер',
avatarURL: 'img/demo-avatar-m.png',
content: '<p>Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты.</p>',
})
+block-lib-code()
......@@ -698,9 +692,6 @@ block content
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/form/form.pug
+block-lib('is-mobile', 'Определение мобильного устройства', false)
include:markdown-it(html='true') ../blocks/is-mobile/readme.md
+block-lib('scroll-link', 'Ссылки на якоря страницы', false)
include:markdown-it(html='true') ../blocks/scroll-link/readme.md
+scroll-link('Описание блока <code>page</code>', '#page')
......@@ -713,69 +704,6 @@ block content
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/to-top/to-top.pug
+block-lib('dropdown', 'Выпадающий элемент', false)
include:markdown-it(html='true') ../blocks/dropdown/readme.md
pre.code
code // Факт открытия
code $('#drop-demo-01').closest('.dropdown').on('shown.nth.dropdown', function () {
code console.log('shown.nth.dropdown');
code });
code
code // Факт закрытия
code $('#drop-demo-01').closest('.dropdown').on('hidden.nth.dropdown', function () {
code console.log('hidden.nth.dropdown');
code });
+dropdown('Дроп (с выводом событий в консоль)', 'drop-demo-01')
p текст
span &nbsp;
+dropdown('Выпадающее меню', 'drop-demo-02', 'up, right')
.menu
span.menu__item
a.menu__link(href='') Пункт списка
span.menu__item
a.menu__link(href='') Пункт меню весьма длинный
span.menu__item
a.menu__link(href='') Второй пункт
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/dropdown/dropdown.pug
+block-lib('owl-carousel', 'Карусель с <a href="http://owlcarousel2.github.io/OwlCarousel2/">owl-carousel</a>', false)
include:markdown-it(html='true') ../blocks/owl-carousel/readme.md
+owl-carousel('promo')
div слайд1
div слайд2
div слайд3
div слайд4
div слайд5
div слайд6
div слайд7
div слайд8
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/owl-carousel/owl-carousel.pug
+block-lib('swipe', 'Карусель с <a href="https://github.com/lyfeyaj/swipe">swipe</a>', false)
include:markdown-it(html='true') ../blocks/swipe/readme.md
+swipe('swipe-demo')
div слайд1
div слайд2
div слайд3
div слайд4
div слайд5
div слайд6
div слайд7
div слайд8
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/swipe/swipe.pug
+block-lib('nouislider', 'Выбор диапазона с <a href="https://refreshless.com/nouislider/">noUiSlider</a>', false)
include:markdown-it(html='true') ../blocks/nouislider/readme.md
+nouislider('demo-nouislider')
p(style='margin-top: 1rem;')
input#demo-nouislider-start(type='number', value='10')
input#demo-nouislider-end(type='number', value='80')
+block-lib-code()
include:show-code(first-line='//- Pug-файл этого блока:') ../blocks/nouislider/nouislider.pug
+block-lib('off-canvas', 'Боковое меню страницы', false)
include:markdown-it(html='true') ../blocks/off-canvas/readme.md
p #[button.btn(type='button', data-toggle='off-canvas') Показать/скрыть боковое меню]
......
......@@ -32,8 +32,6 @@ html(class='no-js page', lang='ru')
link(rel='stylesheet', href='css/style.css')
script.
document.documentElement.className = document.documentElement.className.replace('no-js', 'js');
script
include ../blocks/is-mobile/is-mobile--to-head.js
body
noscript У вас отключен JavaScript. Это пугает.
......@@ -57,4 +55,4 @@ html(class='no-js page', lang='ru')
.off-canvas__overlay(data-toggle='off-canvas')
block page-bottom
script(src='js/script.min.js')
script(src='js/blocks-lib.js')
......@@ -32,8 +32,6 @@ html(class='no-js page', lang='ru')
link(rel='stylesheet', href='css/style.css')
script.
document.documentElement.className = document.documentElement.className.replace('no-js', 'js');
script
include ../blocks/is-mobile/is-mobile--to-head.js
body
noscript У вас отключен JavaScript. Это пугает.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment