├── src ├── helper │ ├── _index.styl │ ├── no.styl │ └── add.styl ├── core │ ├── _index.styl │ ├── typography.styl │ ├── defaults.styl │ └── normalize.styl ├── grid │ ├── _index.styl │ ├── row.styl │ ├── container.styl │ ├── grid.styl │ └── column.styl ├── util │ ├── _index.styl │ ├── colors.styl │ ├── mixins.styl │ ├── functions.styl │ ├── variables.styl │ └── elements-mixins.styl └── components │ ├── radio.styl │ ├── breadcrumb.styl │ ├── icon.styl │ ├── form.styl │ ├── file.styl │ ├── _index.styl │ ├── textarea.styl │ ├── calendar.styl │ ├── datepicker.styl │ ├── tabs.styl │ ├── pagination.styl │ ├── alert.styl │ ├── input.styl │ ├── avatar.styl │ ├── input-icons.styl │ ├── loading.styl │ ├── dropdown.styl │ ├── progress.styl │ ├── input-group.styl │ ├── label.styl │ ├── input-tag.styl │ ├── accordion.styl │ ├── checkbox.styl │ ├── buttons.styl │ ├── navbar.styl │ ├── switcher.styl │ ├── modal.styl │ ├── slider.styl │ ├── tooltip.styl │ ├── nav.styl │ ├── table.styl │ ├── button.styl │ └── select.styl ├── .eslintrc ├── .npmignore ├── extensions ├── .npmignore ├── _utils │ ├── async.js │ ├── call.js │ ├── stringToDOM.js │ ├── hide.js │ ├── show.js │ ├── select.js │ ├── getClosestValue.js │ ├── wrap.js │ ├── isElementClosest.js │ ├── throttle.js │ ├── debounce.js │ └── toArray.js ├── datepicker │ ├── .npmignore │ ├── yarn.lock │ ├── package.json │ ├── index.html │ ├── README.md │ └── src │ │ └── datepicker.js ├── slider │ ├── package.json │ ├── yarn.lock │ ├── README.md │ ├── index.html │ └── src │ │ └── slider.js ├── switcher │ ├── package.json │ ├── README.md │ ├── src │ │ └── switcher.js │ └── index.html ├── table │ ├── package.json │ ├── src │ │ ├── sortable.js │ │ ├── paginator.js │ │ └── table.js │ ├── index.html │ └── README.md ├── navbar │ ├── package.json │ ├── index.html │ ├── README.md │ └── src │ │ └── navbar.js ├── modal │ ├── package.json │ ├── src │ │ └── modal.js │ ├── README.md │ └── index.html ├── package.json ├── select │ ├── package.json │ ├── README.md │ ├── index.html │ └── src │ │ └── select.js ├── accordion │ ├── package.json │ ├── README.md │ ├── src │ │ └── accordion.js │ └── index.html ├── dropdown │ ├── package.json │ ├── src │ │ └── dropdown.js │ ├── README.md │ └── index.html └── README.md ├── blexar.styl ├── .gitignore ├── .babelrc ├── scripts ├── watcher.js ├── config.js ├── styles.js └── extensions.js ├── LICENSE ├── README.md └── package.json /src/helper/_index.styl: -------------------------------------------------------------------------------- 1 | @import 'add' 2 | @import 'no' -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "standard" 4 | ] 5 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | Icon 3 | node_modules 4 | /test 5 | yarn.lock 6 | extensions -------------------------------------------------------------------------------- /src/core/_index.styl: -------------------------------------------------------------------------------- 1 | @import 'normalize' 2 | @import 'typography' 3 | @import 'defaults' 4 | 5 | -------------------------------------------------------------------------------- /src/grid/_index.styl: -------------------------------------------------------------------------------- 1 | @import 'container' 2 | @import 'column' 3 | @import 'grid' 4 | @import 'row' -------------------------------------------------------------------------------- /src/grid/row.styl: -------------------------------------------------------------------------------- 1 | .row 2 | @extends .grid 3 | width: 100% 4 | justify-content: inherit 5 | margin: 0 6 | -------------------------------------------------------------------------------- /extensions/.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | Icon/r 3 | node_modules 4 | */**/node_modules 5 | yarn.lock 6 | */**/src 7 | */**/index.html 8 | _utils -------------------------------------------------------------------------------- /extensions/_utils/async.js: -------------------------------------------------------------------------------- 1 | export default function async (callback) { 2 | setTimeout(() => callback(), 1000 / 60); 3 | } 4 | -------------------------------------------------------------------------------- /src/util/_index.styl: -------------------------------------------------------------------------------- 1 | @import 'functions' 2 | @import 'variables' 3 | @import 'colors' 4 | @import 'mixins' 5 | @import 'elements-mixins' 6 | 7 | -------------------------------------------------------------------------------- /extensions/datepicker/.npmignore: -------------------------------------------------------------------------------- 1 | /build 2 | /docs 3 | /src/stylus 4 | /static 5 | .eslintrc.json 6 | .gitignore 7 | yarn.lock 8 | gulpfile.js 9 | node_modules -------------------------------------------------------------------------------- /extensions/_utils/call.js: -------------------------------------------------------------------------------- 1 | export default function call (func, args = null) { 2 | if (typeof func === 'function') { 3 | func(args); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /extensions/_utils/stringToDOM.js: -------------------------------------------------------------------------------- 1 | export default function stringToDOM (string) { 2 | return document.createRange().createContextualFragment(string).firstElementChild; 3 | } 4 | -------------------------------------------------------------------------------- /blexar.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * core 3 | */ 4 | @import 'src/util/_index' 5 | @import 'src/core/_index' 6 | @import 'src/grid/_index' 7 | @import 'src/components/_index' 8 | @import 'src/helper/_index' 9 | -------------------------------------------------------------------------------- /extensions/_utils/hide.js: -------------------------------------------------------------------------------- 1 | export default function hide (el) { 2 | el.classList.remove('is-visible'); 3 | el.classList.add('is-hidden'); 4 | el.setAttribute('aria-hidden', 'true'); 5 | } 6 | -------------------------------------------------------------------------------- /extensions/_utils/show.js: -------------------------------------------------------------------------------- 1 | export default function show (el) { 2 | el.classList.add('is-visible'); 3 | el.classList.remove('is-hidden'); 4 | el.setAttribute('aria-hidden', 'false'); 5 | } 6 | -------------------------------------------------------------------------------- /extensions/_utils/select.js: -------------------------------------------------------------------------------- 1 | export default function select (element) { 2 | if (typeof element === 'string') { 3 | return document.querySelector(element); 4 | } 5 | return element; 6 | } 7 | -------------------------------------------------------------------------------- /extensions/_utils/getClosestValue.js: -------------------------------------------------------------------------------- 1 | export default function getClosestValue (array, value) { 2 | return array.reduce((prev, curr) => { 3 | return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev 4 | }); 5 | } 6 | -------------------------------------------------------------------------------- /extensions/_utils/wrap.js: -------------------------------------------------------------------------------- 1 | export default function wrap (el, wrapper) { 2 | // insert wrapper before el in the DOM tree 3 | el.parentNode.insertBefore(wrapper, el); 4 | 5 | // move el into wrapper 6 | wrapper.appendChild(el); 7 | } 8 | -------------------------------------------------------------------------------- /extensions/slider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/slider", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "dist/slider.js", 6 | "module": "dist/slider.esm.js", 7 | "keywords": [], 8 | "license": "MIT" 9 | } 10 | -------------------------------------------------------------------------------- /extensions/switcher/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/switcher", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "dist/switcher.js", 6 | "module": "dist/switcher.esm.js", 7 | "author": "", 8 | "license": "MIT" 9 | } 10 | -------------------------------------------------------------------------------- /extensions/table/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/table", 3 | "version": "0.0.0", 4 | "description": "Blexar framework table extension.", 5 | "main": "dist/table.js", 6 | "modules": "dist/table.js", 7 | "author": "", 8 | "license": "MIT" 9 | } 10 | -------------------------------------------------------------------------------- /extensions/_utils/isElementClosest.js: -------------------------------------------------------------------------------- 1 | export default function isElementClosest (element, wrapper) { 2 | while (element !== document && element !== null) { 3 | if (element === wrapper) return true; 4 | element = element.parentNode; 5 | } 6 | return false; 7 | } 8 | -------------------------------------------------------------------------------- /extensions/slider/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | color-fns@^0.0.4: 6 | version "0.0.4" 7 | resolved "https://registry.yarnpkg.com/color-fns/-/color-fns-0.0.4.tgz#065f20675ba0ec923580759dcd0f1d172f8df612" 8 | -------------------------------------------------------------------------------- /extensions/datepicker/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | date-fns@^2.0.0-alpha.7: 6 | version "2.0.0-alpha.7" 7 | resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.0.0-alpha.7.tgz#245ad16f95764eababfb2c0a41fd5d033c20e57a" 8 | -------------------------------------------------------------------------------- /extensions/navbar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/navbar", 3 | "version": "0.0.0", 4 | "description": "Adaptive navbar that move navbar elements to dropdown menu based on pre-order priorities.", 5 | "main": "dist/navbar.js", 6 | "keywords": [ 7 | "navbar" 8 | ], 9 | "license": "MIT" 10 | } 11 | -------------------------------------------------------------------------------- /extensions/datepicker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/datepicker", 3 | "main": "dist/datepicker.js", 4 | "module": "dist/datepicker.esm.js", 5 | "version": "0.0.0", 6 | "maintainers": [ 7 | { 8 | "name": "Abdelrahman3D", 9 | "email": "abdelrahman3d@gmail.com" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Test foloder 9 | test/ 10 | 11 | # Dependency directories 12 | node_modules/ 13 | 14 | # Yarn Integrity file 15 | .yarn-integrity 16 | 17 | # macOS folder icon 18 | Icon/ 19 | 20 | # dit folders 21 | dist 22 | */**/dist -------------------------------------------------------------------------------- /extensions/modal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/modal", 3 | "version": "0.0.0", 4 | "description": "Blexar framework modal extension", 5 | "main": "dist/modal.js", 6 | "module": "dist/modal.es.js", 7 | "keywords": [ 8 | "modal", 9 | "es6" 10 | ], 11 | "author": "", 12 | "license": "MIT" 13 | } 14 | -------------------------------------------------------------------------------- /src/components/radio.styl: -------------------------------------------------------------------------------- 1 | .radio 2 | @extends .checkbox 3 | 4 | &-input 5 | border-radius: 10em 6 | 7 | &:after 8 | width: 30% 9 | height: 30% 10 | border: none 11 | border-radius: 10em 12 | background: $white 13 | transform: none 14 | 15 | input.radio 16 | @extends .radio-input -------------------------------------------------------------------------------- /extensions/_utils/throttle.js: -------------------------------------------------------------------------------- 1 | export default function throttle (callback, limit) { 2 | let wait = false; 3 | return () => { 4 | if (!wait) { 5 | callback.apply(this, arguments); 6 | wait = true; 7 | setTimeout(() => { 8 | wait = false; 9 | }, limit); 10 | } 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /extensions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/extensions", 3 | "version": "0.0.2", 4 | "license": "MIT", 5 | "keywords": [], 6 | "maintainers": [ 7 | { 8 | "name": "Abdelrahman3D", 9 | "email": "abdelrahman3d@gmail.com" 10 | } 11 | ], 12 | "dependencies": { 13 | "color-fns": "0.0.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ], 10 | "plugins": [ 11 | "external-helpers", 12 | "transform-class-properties", 13 | [ "transform-object-rest-spread", 14 | { 15 | "useBuiltIns": true 16 | } 17 | ] 18 | ] 19 | } -------------------------------------------------------------------------------- /extensions/select/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eidtor", 3 | "version": "0.0.1", 4 | "description": "ES6 select", 5 | "main": "dist/select.js", 6 | "dependencies": {}, 7 | "author": "", 8 | "license": "MIT", 9 | "keywords": [], 10 | "maintainers": [ 11 | { 12 | "name": "Abdelrahman3D", 13 | "email": "abdelrahman3d@gmail.com" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /extensions/accordion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/accordion", 3 | "version": "0.0.0", 4 | "description": "Blexar framework accordion extension", 5 | "main": "dist/accordion.js", 6 | "module": "dist/accordion.esm.js", 7 | "author": "", 8 | "license": "MIT", 9 | "maintainers": [ 10 | { 11 | "name": "Abdelrahman3D", 12 | "email": "abdelrahman3d@gmail.com" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /extensions/dropdown/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/dropdown", 3 | "version": "0.0.0", 4 | "description": "Blexar framework dropdown menu extension", 5 | "author": "", 6 | "main": "dist/js/dropdown.js", 7 | "module": "dist/js/dropdown.esm.js", 8 | "license": "MIT", 9 | "keywords": [], 10 | "maintainers": [ 11 | { 12 | "name": "Abdelrahman3D", 13 | "email": "abdelrahman3d@gmail.com" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /extensions/_utils/debounce.js: -------------------------------------------------------------------------------- 1 | export default function debounce (func, immediate = false) { 2 | let timeout; 3 | return function () { 4 | let later = () => { 5 | timeout = null; 6 | if (!immediate) func(...arguments); 7 | }; 8 | let callNow = immediate && !timeout; 9 | window.cancelAnimationFrame(timeout); 10 | timeout = window.requestAnimationFrame(later); 11 | if (callNow) func(...arguments); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/breadcrumb.styl: -------------------------------------------------------------------------------- 1 | .breadcrumb 2 | display: flex 3 | list-style: none 4 | margin: 0 5 | padding: 0 6 | // generate size modifiers 7 | generateSizes() 8 | 9 | li 10 | margin-top: 0 11 | 12 | .breadcrumb-divider 13 | padding: 0 $padding 14 | color: $gray 15 | _icon-color: $gray 16 | 17 | .breadcrumb-item 18 | color: $primary 19 | 20 | &.is-active 21 | color: $slategray 22 | font-weight: $font-weight-semi-bold 23 | -------------------------------------------------------------------------------- /src/grid/container.styl: -------------------------------------------------------------------------------- 1 | .container 2 | width: $container-mobile 3 | margin: auto 4 | padding-left: $gutter 5 | padding-right: $gutter 6 | 7 | +tablet() 8 | width: $container-tablet 9 | 10 | +desktop() 11 | width: $container-desktop 12 | 13 | +widescreen() 14 | width: $container-widescreen 15 | 16 | +ultrawide() 17 | width: $container-ultrawide 18 | 19 | .container-full 20 | width: 100% 21 | padding-left: $gutter-full 22 | padding-right: $gutter-full -------------------------------------------------------------------------------- /extensions/_utils/toArray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts an array-like object to an array. 3 | */ 4 | export default function toArray (arrayLike, mappingFn) { 5 | if (Array.from) { 6 | return Array.from(arrayLike, mappingFn); 7 | } 8 | 9 | const array = []; 10 | const shouldMap = typeof mappingFn === 'function'; 11 | const length = arrayLike.length; 12 | for (let i = 0; i < length; i++) { 13 | array.push(shouldMap ? mappingFn(arrayLike[i]) : arrayLike[i]); 14 | } 15 | 16 | return array; 17 | } 18 | -------------------------------------------------------------------------------- /src/helper/no.styl: -------------------------------------------------------------------------------- 1 | .no 2 | &-padding 3 | padding: 0 !important 4 | &-paddingTop 5 | padding-top: 0 !important 6 | &-paddingBottom 7 | padding-bottom: 0 !important 8 | &-paddingRight 9 | padding-right: 0 !important 10 | &-paddingLeft 11 | padding-left: 0 !important 12 | 13 | &-margin 14 | margin: 0 !important 15 | &-marginTop 16 | margin-top: 0 !important 17 | &-marginBottom 18 | margin-bottom: 0 !important 19 | &-marginRight 20 | margin-right: 0 !important 21 | &-marginLeft 22 | margin-left: 0 !important -------------------------------------------------------------------------------- /src/components/icon.styl: -------------------------------------------------------------------------------- 1 | .icon 2 | display: inline-block 3 | vertical-align: middle 4 | line-height: inherit 5 | font-size: 1em 6 | width: 1em 7 | height: 1em 8 | &:not(:last-child) 9 | margin-{$dir-end}: $margin 10 | 11 | // generate color modifiers 12 | for color in $modifiers-color 13 | $color = lookup('$' + color) 14 | &.is-{color} 15 | _icon-color: $color 16 | 17 | // generate size modifiers 18 | for size in $modifiers-size 19 | $size = lookup('$size-' + size) 20 | &.is-{size} 21 | width: $size 22 | height: $size 23 | -------------------------------------------------------------------------------- /src/components/form.styl: -------------------------------------------------------------------------------- 1 | .form 2 | &.is-inline 3 | .field 4 | display: flex 5 | 6 | .field 7 | margin-bottom: ($margin * 2) 8 | >:last-child 9 | margin-bottom: 0 10 | 11 | .field-label 12 | font-weight: $font-weight-semi-bold 13 | display: block 14 | margin-bottom: $margin 15 | margin-top: $margin 16 | 17 | .field-text 18 | display: block 19 | font-size: 0.75em 20 | margin-bottom: $margin 21 | color: $gray 22 | // generate color modifiers 23 | for color in $modifiers-color 24 | $accent = lookup('$' + color) 25 | &.is-{color} 26 | color: $accent -------------------------------------------------------------------------------- /src/components/file.styl: -------------------------------------------------------------------------------- 1 | .file 2 | margin-bottom: $margin 3 | padding: $padding ($padding * 1.5) 4 | width: 100% 5 | border: 1px solid $gray 6 | border-radius: $border-radius 7 | line-height: $element-lineheight 8 | display: inline-block 9 | cursor: pointer 10 | color: $dark 11 | _icon-color: $dark 12 | 13 | // generate size modifiers 14 | generateSizes() 15 | 16 | // generate color modifiers 17 | for color in $modifiers-color 18 | $accent = lookup('$' + color) 19 | $text = isLight(color) ? $black : $white 20 | &.is-{color} 21 | _file-color: $accent $text 22 | 23 | 24 | .file-input 25 | display: none -------------------------------------------------------------------------------- /scripts/watcher.js: -------------------------------------------------------------------------------- 1 | const { buildStyles } = require('./styles'); 2 | const { buildScripts } = require('./extensions'); 3 | const bs = require('browser-sync').create(); 4 | 5 | bs.watch('*/**/*.html').on('change', bs.reload); 6 | 7 | bs.watch('*/**/*.styl', function (event, file) { 8 | if (event === 'change') { 9 | buildStyles(); 10 | bs.reload(); 11 | } 12 | }); 13 | 14 | bs.watch('*/**/src/*.js', function (event, file) { 15 | if (event === 'change') { 16 | const fileName = file.match(/(\w+).js$/)[1]; 17 | buildScripts('umd', fileName); 18 | bs.reload(); 19 | } 20 | }); 21 | 22 | bs.init({ 23 | server: true 24 | }); 25 | -------------------------------------------------------------------------------- /src/components/_index.styl: -------------------------------------------------------------------------------- 1 | @import 'button' 2 | @import 'buttons' 3 | @import 'label' 4 | @import 'icon' 5 | @import 'input' 6 | @import 'input-tag' 7 | @import 'input-group' 8 | @import 'input-icons' 9 | @import 'file' 10 | @import 'checkbox' 11 | @import 'radio' 12 | @import 'switcher' 13 | @import 'table' 14 | @import 'textarea' 15 | @import 'tooltip' 16 | @import 'nav' 17 | @import 'select' 18 | @import 'dropdown' 19 | @import 'modal' 20 | @import 'navbar' 21 | @import 'pagination' 22 | @import 'accordion' 23 | @import 'calendar' 24 | @import 'datepicker' 25 | @import 'slider' 26 | @import 'loading' 27 | @import 'progress' 28 | @import 'avatar' 29 | @import 'form' 30 | @import 'alert' 31 | @import 'tabs' 32 | @import 'breadcrumb' 33 | -------------------------------------------------------------------------------- /src/components/textarea.styl: -------------------------------------------------------------------------------- 1 | .textarea 2 | display: block 3 | margin-bottom: $margin 4 | padding: $padding 5 | min-width: 100% 6 | max-width: 100% 7 | outline: none 8 | border-width: $border 9 | border-style: solid 10 | border-radius: $border-radius 11 | text-align: $dir-start 12 | line-height: 1.2 13 | _textarea-color: $gray $primary 14 | 15 | // generate size modifiers 16 | generateSizes() 17 | 18 | // generate color modifiers 19 | for color in $modifiers-color 20 | $color = lookup('$' + color) 21 | &.is-{color} 22 | _textarea-color: $color 23 | 24 | &:disabled, &.is-disabled 25 | cursor: not-allowed 26 | background: $gray 27 | color: $white 28 | pointer-events: none 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/components/calendar.styl: -------------------------------------------------------------------------------- 1 | .calendar 2 | padding: $padding 3 | border-radius: $border-radius 4 | background-color: $white 5 | border-spacing: 0 6 | text-align: center 7 | 8 | generateSizes() 9 | 10 | td 11 | padding: 0.25em 12 | border-width: $border 13 | border-style: solid 14 | border-color: $white 15 | border-radius: $border-radius 16 | cursor: pointer 17 | 18 | &.is-previous, 19 | &.is-following 20 | color: $gray 21 | 22 | &.is-active 23 | border-color: $primary 24 | background-color: $primary 25 | color: $white 26 | 27 | &:hover, 28 | &:focus 29 | border-color: $primary 30 | 31 | th 32 | padding: 10px 5px 33 | color: $slategray 34 | font-size: 0.7em 35 | -------------------------------------------------------------------------------- /src/helper/add.styl: -------------------------------------------------------------------------------- 1 | .u 2 | &-sticky 3 | position: sticky 4 | top: $margin 5 | 6 | &-float-right 7 | float: right 8 | 9 | &-float-left 10 | float: left 11 | 12 | &-flex 13 | display: flex 14 | 15 | &-justify-center 16 | justify-content: center 17 | 18 | &-justify-end 19 | justify-content: flex-end 20 | 21 | &-justify-start 22 | justify-content: flex-start 23 | 24 | &-justify-around 25 | justify-content: space-around 26 | 27 | &-justify-between 28 | justify-content: space-between 29 | 30 | &-align-center 31 | align-items: center 32 | 33 | &-align-end 34 | align-items: flex-end 35 | 36 | &-align-start 37 | align-items: flex-start 38 | 39 | &-align-baseline 40 | align-items: baseline 41 | 42 | &-align-stretch 43 | align-items: stretch 44 | -------------------------------------------------------------------------------- /src/components/datepicker.styl: -------------------------------------------------------------------------------- 1 | .datepicker 2 | margin-bottom: $margin 3 | padding: $padding multiple($padding, 1.5) 4 | width: 100% 5 | border: $border solid $black 6 | border-radius: $border-radius 7 | generateSizes() 8 | 9 | &-control 10 | display: flex 11 | justify-content: space-between 12 | align-items: center 13 | width: 100% 14 | padding: 0 $padding 15 | 16 | select, 17 | input 18 | padding: 5px 10px 19 | width: 50% 20 | border-width: 0 0 $border 0 21 | border-color: $white 22 | color: $slategray 23 | border-radius: 0 24 | background-color: transparent 25 | text-align: center 26 | text-align-last: center 27 | font-size: 0.8em 28 | -webkit-appearance: none 29 | 30 | &:hover, 31 | &:focus 32 | outline: 0 33 | border-color: $black 34 | -------------------------------------------------------------------------------- /src/util/colors.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * colors 3 | */ 4 | $magenta ?= #F2248F 5 | $blue ?= #2451F2 6 | $cyan ?= #3D8EF2 7 | $green ?= #36D9B0 8 | $yellow ?= #FFCF0D 9 | $orange ?= #FF6F00 10 | $red ?= #F22435 11 | $aqua ?= #00FCFE 12 | 13 | /** 14 | * Graysacle 15 | */ 16 | $black ?= #000000 17 | $dark ?= #383555 18 | $slategray ?= #9D99BC 19 | $gray ?= #E9E8F2 20 | $light ?= #F6F5FD 21 | $white ?= #FFFFFF 22 | 23 | /** 24 | * theme colors 25 | */ 26 | $primary ?= $blue 27 | $secondary ?= $magenta 28 | $danger ?= $red 29 | $success ?= $green 30 | $warning ?= $yellow 31 | $info ?= $cyan 32 | $link ?= $blue 33 | $link-hover ?= $black 34 | 35 | /** 36 | * Gradient colors 37 | */ 38 | $grad-direction ?= 45deg 39 | $grad-primary ?= $blue, $magenta 40 | $grad-secondary ?= $magenta, $orange 41 | $grad-success ?= $green, $magenta 42 | $grad-danger ?= $red, $magenta 43 | $grad-warning ?= $yellow, $green 44 | $grad-info ?= $aqua, $blue 45 | -------------------------------------------------------------------------------- /extensions/modal/src/modal.js: -------------------------------------------------------------------------------- 1 | import select from '../../_utils/select'; 2 | import show from '../../_utils/show'; 3 | import hide from '../../_utils/hide'; 4 | 5 | /** 6 | * modal class 7 | */ 8 | export default class Modal { 9 | constructor(selector, button) { 10 | this.el = select(selector); 11 | this.button = select(button); 12 | this.init(); 13 | } 14 | 15 | init() { 16 | this.panel = this.el.querySelector('.modal-panel'); 17 | this.dismiss = this.el.querySelector('.modal-dismiss'); 18 | this.animating = false; 19 | 20 | this.initEvents(); 21 | hide(this.el); 22 | } 23 | 24 | initEvents() { 25 | this.button.addEventListener('click', () => show(this.el), false); 26 | this.dismiss.addEventListener('click', () => hide(this.el), false); 27 | 28 | this.el.addEventListener('click', (event) => { 29 | if (event.target === this.el) hide(this.el); 30 | }, false); 31 | } 32 | } -------------------------------------------------------------------------------- /src/components/tabs.styl: -------------------------------------------------------------------------------- 1 | .tabs 2 | display: flex 3 | list-style: none 4 | margin: 0 5 | padding: ($padding * 2) 0 6 | border-bottom: 1px solid $gray 7 | li 8 | margin: 0 9 | a 10 | border-top-right-radius: $border-radius 11 | border-top-left-radius: $border-radius 12 | padding: ($padding * 2) 13 | background-color: $white 14 | color: $slategray 15 | _icon-color: $slategray 16 | .icon 17 | margin-right: 0 18 | 19 | .is-active a 20 | a:hover 21 | border-bottom: 2px solid $primary 22 | color: $primary 23 | _icon-color: $primary 24 | 25 | &.is-centered 26 | justify-content: center 27 | &.is-end 28 | justify-content: flex-end 29 | 30 | &.is-boxed 31 | a 32 | border: 1px solid transparent 33 | border-bottom: 0 34 | .is-active a 35 | a:hover 36 | border: 1px solid $gray 37 | border-bottom-color: transparent -------------------------------------------------------------------------------- /scripts/config.js: -------------------------------------------------------------------------------- 1 | const babel = require('rollup-plugin-babel'); 2 | const resolve = require('rollup-plugin-node-resolve'); 3 | const replace = require('rollup-plugin-replace'); 4 | 5 | const { version } = require('../package.json'); 6 | 7 | module.exports = { 8 | extensions: [ 9 | 'dropdown', 10 | 'slider', 11 | 'datepicker', 12 | 'accordion', 13 | 'modal', 14 | 'navbar', 15 | 'select', 16 | 'switcher', 17 | 'table' 18 | ], 19 | script: { 20 | banner: 21 | `/** 22 | * v${version} 23 | * (c) ${new Date().getFullYear()} Baianat 24 | * @license MIT 25 | */`, 26 | uglifyOptions: { 27 | toplevel: true, 28 | compress: true, 29 | mangle: true 30 | }, 31 | inputOptions: { 32 | plugins: [ 33 | replace({ __VERSION__: version }), 34 | babel(), 35 | resolve() 36 | ] 37 | } 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /src/components/pagination.styl: -------------------------------------------------------------------------------- 1 | .pagination 2 | display: flex 3 | align-items: top 4 | margin: $margin 0 5 | flex-wrap: wrap 6 | 7 | &-item, &-next, &-prev, &-first, &-last 8 | position: relative 9 | display: inline-flex 10 | justify-content: center 11 | align-items: center 12 | width: 2em 13 | height: 2em 14 | outline-width: 0 15 | outline-offset: 0 16 | border: none 17 | text-decoration: none 18 | cursor: pointer 19 | background: $white 20 | font-size: inherit 21 | _icon-color: $black 22 | @extends $normal 23 | 24 | &.is-active, &:active, &:hover:not(.is-disabled) 25 | color: $primary 26 | _icon-color: $primary 27 | 28 | &.is-disabled 29 | border-color: $gray 30 | color: $gray 31 | _icon-color: $gray 32 | 33 | &:focus 34 | outline-color: 0 35 | 36 | .icon 37 | width: 1.4em 38 | height: 1.4em 39 | 40 | generateSizes() -------------------------------------------------------------------------------- /src/components/alert.styl: -------------------------------------------------------------------------------- 1 | .alert 2 | position: relative 3 | display: flex 4 | align-items: center 5 | padding: 0.75em 6 | border-radius: 1.5em 7 | margin-bottom: $margin 8 | _alert-color: $gray $dark 9 | 10 | // generate color modifiers 11 | for color in $modifiers-color 12 | $accent = lookup('$' + color) 13 | $text = isLight(color) ? $black : $white 14 | 15 | &.is-{color} 16 | _alert-color: $accent $text 17 | 18 | &.is-outlined 19 | background-color: transparent 20 | border-style: solid 21 | border-width: $border 22 | 23 | &.is-float 24 | box-shadow: boxShadow(large) 25 | 26 | .alert-dismiss 27 | margin-{$dir-start}: $margin 28 | padding: 0 29 | border: 0 30 | background-color: transparent 31 | cursor: pointer 32 | _icon-color: inherit 33 | 34 | &:focus 35 | outline: none 36 | 37 | &:hover 38 | _icon-color: $primary 39 | 40 | .alert-content 41 | flex: 1 1 0% -------------------------------------------------------------------------------- /extensions/datepicker/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Blexar Datepicker 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

Blexar Datepicker

15 |

A datepicker allows users to select specific date

16 |
17 |
18 |
19 |

Default

20 |
21 |
22 | 23 |
24 |
25 |
26 | 27 | 28 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/core/typography.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * Variables 3 | */ 4 | 5 | $display-1 ?= $font-size[13] 6 | $display-2 ?= $font-size[12] 7 | $display-3 ?= $font-size[11] 8 | $display-4 ?= $font-size[10] 9 | 10 | $header-1 ?= $font-size[8] 11 | $header-2 ?= $font-size[7] 12 | $header-3 ?= $font-size[6] 13 | $header-4 ?= $font-size[5] 14 | $header-5 ?= $font-size[4] 15 | $header-6 ?= $font-size[3] 16 | 17 | $header-defaults 18 | margin-top: 0 19 | margin-bottom: 0.5em 20 | line-height: $lineheight 21 | font-weight: $font-weight-semi-bold 22 | 23 | /** 24 | * Elements 25 | */ 26 | 27 | for $n in (1..6) 28 | h{$n}, .h{$n} 29 | font-size: lookup('$header-' + $n) 30 | @extends $header-defaults 31 | 32 | for $n in (1..3) 33 | h{$n}, .h{$n} 34 | &:not(:first-child) 35 | margin-top: 1em 36 | 37 | for $n in (1..4) 38 | .display-{$n} 39 | font-size: lookup('$display-' + $n) 40 | &:not(:first-child) 41 | margin-top: 1em 42 | 43 | p, html 44 | @extends $normal -------------------------------------------------------------------------------- /src/components/input.styl: -------------------------------------------------------------------------------- 1 | .input 2 | margin-bottom: $margin 3 | padding: $padding ($padding * 1.5) 4 | width: 100% 5 | outline: none 6 | border-width: $border 7 | border-style: solid 8 | border-radius: $border-radius 9 | background-color: $white 10 | line-height: $element-lineheight 11 | -webkit-appearance: none 12 | -moz-appearance: none 13 | _input-color: $gray $dark 14 | &:focus 15 | z-index: 1 16 | 17 | // generate size modifiers 18 | generateSizes() 19 | 20 | // generate color modifiers 21 | for color in $modifiers-color 22 | $color = lookup('$' + color) 23 | &.is-{color} 24 | _input-color: $color 25 | 26 | &.is-block 27 | width: 100% 28 | 29 | &.is-rounded 30 | border-radius: 10em 31 | 32 | &.is-bold 33 | border-width: 2px 34 | &:disabled, 35 | &.is-disabled 36 | cursor: not-allowed 37 | background: $gray 38 | 39 | &.is-disabled 40 | pointer-events: none 41 | 42 | &[type="color"] 43 | padding: 0 -------------------------------------------------------------------------------- /src/components/avatar.styl: -------------------------------------------------------------------------------- 1 | .avatar 2 | position: relative 3 | width: 3em 4 | height: 3em 5 | margin: 0 6 | generateSizes() 7 | 8 | &:not(:first-child) 9 | &:not(:last-child) 10 | margin: 0 11 | 12 | img 13 | display: block 14 | border-radius: 10em 15 | margin: 0 16 | width: 100% 17 | height: 100% 18 | object-fit: cover 19 | 20 | .avatar-initials 21 | border-radius: 10em 22 | display: block 23 | line-height: 3 24 | text-align: center 25 | background-color: $primary 26 | color: $white 27 | font-weight: $font-weight-semi-bold 28 | 29 | .avatar-icon 30 | position: absolute 31 | bottom: 3% 32 | right: 3% 33 | display: block 34 | border-radius: 10em 35 | width: 0.75em 36 | height: 0.75em 37 | border: 2px solid $white 38 | background: $gray 39 | // generate color modifiers 40 | for color in $modifiers-color 41 | $accent = lookup('$' + color) 42 | &.is-{color} 43 | background: $accent -------------------------------------------------------------------------------- /extensions/table/src/sortable.js: -------------------------------------------------------------------------------- 1 | import select from '../../_utils/select'; 2 | 3 | class Sortable { 4 | constructor(el, paginator, { 5 | paginate = true 6 | } = {}) { 7 | 8 | this.el = select(el); 9 | this.settings = { 10 | paginate 11 | }; 12 | this.paginator = paginator; 13 | this.init(); 14 | } 15 | 16 | /** 17 | * initializes the table 18 | */ 19 | init() { 20 | if (this.settings.paginate) { 21 | this.paginator.render(); 22 | } 23 | } 24 | 25 | /** 26 | * sorts by a specific column. 27 | */ 28 | sortBy(property, order = 'asc') { 29 | const desiredOrder = order.toLowerCase(); 30 | this.paginator.items.sort((a, b) => { 31 | if (a[property] > b[property]) { 32 | return desiredOrder === 'asc' ? 1 : -1; 33 | } 34 | 35 | if (a[property] < b[property]) { 36 | return desiredOrder === 'asc' ? -1 : 1; 37 | } 38 | 39 | return 0; 40 | }); 41 | 42 | this.paginator.render(); 43 | } 44 | } 45 | 46 | export default Sortable; 47 | -------------------------------------------------------------------------------- /src/components/input-icons.styl: -------------------------------------------------------------------------------- 1 | .input-icons 2 | position: relative 3 | margin-bottom: $margin 4 | 5 | &.has-icons-after 6 | .input 7 | padding-{$dir-end}: 2.5em 8 | 9 | &.has-icons-before 10 | .input 11 | padding-{$dir-start}: 2.5em 12 | 13 | .input 14 | margin-bottom: 0 15 | 16 | .is-before, .is-after 17 | position: absolute 18 | top: 50% 19 | transform: translateY(-50%) 20 | fill: $gray 21 | 22 | .is-after 23 | {$dir-end}: 0.75em 24 | 25 | .is-before 26 | {$dir-start}: 0.75em 27 | 28 | .input:focus ~ * 29 | fill: currentColor 30 | 31 | for color in $modifiers-color 32 | $accentColor = lookup('$' + color) 33 | 34 | &.is-{color} 35 | color: $accentColor 36 | 37 | >.input 38 | @extend .input.is-{color} 39 | 40 | >.icon 41 | @extend .icon.is-{color} !optional 42 | 43 | for size in $modifiers-size 44 | &.is-{size} 45 | >.input 46 | @extend .input.is-{size} !optional 47 | 48 | >.icon 49 | @extend .icon.is-{size} !optional 50 | -------------------------------------------------------------------------------- /src/util/mixins.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * media queries mixins 3 | */ 4 | 5 | responsive(breakpoint) 6 | @media screen and (min-width: breakpoint) 7 | {block} 8 | 9 | ultrawide() 10 | @media screen and (min-width: $ultrawide) 11 | {block} 12 | 13 | widescreen() 14 | @media screen and (min-width: $widescreen) 15 | {block} 16 | 17 | desktop() 18 | @media screen and (min-width: $desktop) 19 | {block} 20 | 21 | tablet() 22 | @media screen and (min-width: $tablet) 23 | {block} 24 | 25 | mobile() 26 | @media screen and (max-width: (($tablet - 1))) 27 | {block} 28 | 29 | 30 | /** 31 | * modifiers mixins 32 | */ 33 | 34 | $tiny 35 | font-size $size-tiny 36 | $small 37 | font-size $size-small 38 | $normal 39 | font-size $size-normal 40 | $large 41 | font-size $size-large 42 | $massive 43 | font-size $size-massive 44 | 45 | generateSizes() 46 | &.is-tiny 47 | @extends $tiny 48 | &.is-small 49 | @extends $small 50 | &, 51 | &.is-normal 52 | @extends $normal 53 | &.is-large 54 | @extends $large 55 | &.is-massive 56 | @extends $massive -------------------------------------------------------------------------------- /src/components/loading.styl: -------------------------------------------------------------------------------- 1 | .loading-spinner 2 | .is-loading 3 | position: relative 4 | pointer-events: none 5 | user-select: none 6 | &:after 7 | position: absolute 8 | z-index: 9999 9 | content: '' 10 | display: block 11 | width: 0.7em 12 | height: 0.7em 13 | top: calc(50% - (1em / 2)) 14 | left: calc(50% - (1em / 2)) 15 | border-radius: 2em 16 | border-width: 0.15em 17 | border-top-color: transparent 18 | border-right-color: transparent 19 | border-bottom-color: $primary 20 | border-left-color: $primary 21 | border-style: solid 22 | animation: spinner-rotation 750ms infinite 23 | animation-timing-function: cubic-bezier(.68,-0.55,.27,1.55) 24 | 25 | .loading-spinner 26 | width: 0.7em 27 | height: 0.7em 28 | 29 | .is-loading 30 | color: transparent !important 31 | fill: transparent !important 32 | // generate color modifiers 33 | for color in $modifiers-color 34 | $color = isLight(color) ? $black : $white 35 | &.is-{color}:after 36 | border-bottom-color: $color 37 | border-left-color: $color 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Baianat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/dropdown.styl: -------------------------------------------------------------------------------- 1 | .dropdown 2 | position: relative 3 | display: flex 4 | flex-direction: column 5 | align-items: flex-start 6 | &.is-active .dropdown-menu 7 | transform: scale(1) 8 | 9 | &.is-right 10 | align-items: flex-end 11 | .dropdown-menu 12 | transform-origin: top right 13 | 14 | &.is-center 15 | align-items: center 16 | .dropdown-menu 17 | transform-origin: top center 18 | 19 | .dropdown-toggle.button 20 | marign: 0 21 | 22 | .dropdown-item 23 | display: block 24 | padding: $padding (2 * $padding) 25 | color: $black 26 | &:hover 27 | background-color: $light 28 | color: $black 29 | &.is-active, 30 | &:focus, 31 | &:active 32 | color: $white 33 | background-color: $primary 34 | 35 | .dropdown-menu 36 | display: flex 37 | flex-direction: column 38 | padding: $padding 0 39 | max-width: 250px 40 | border-radius: $border-radius 41 | background-color: $white 42 | color: $dark 43 | transform-origin: top left 44 | user-select: none 45 | margin: 0 46 | box-shadow: boxShadow(small) 47 | transform: scale(0) 48 | &:empty 49 | display: none -------------------------------------------------------------------------------- /extensions/README.md: -------------------------------------------------------------------------------- 1 | # base.extensions 2 | 3 | **A collection of ES6 extensions for Base framework.** 4 | 5 | We've built some extensions to add the necessary functionality and improve current components based on user experience needs. 6 | 7 | ## Current extensions 8 | 9 | * [Accordion](https://github.com/baianat/base.extensions/tree/master/accordion) 10 | * [Colorpicker](https://github.com/baianat/base.extensions/tree/master/colorpicker) 11 | * [Datepicker](https://github.com/baianat/base.extensions/tree/master/datepicker) 12 | * [Dropdown](https://github.com/baianat/base.extensions/tree/master/dropdown) 13 | * [Modal](https://github.com/baianat/base.extensions/tree/master/modal) 14 | * [Navbar](https://github.com/baianat/base.extensions/tree/master/navbar) 15 | * [Select](https://github.com/baianat/base.extensions/tree/master/select) 16 | * [Slider](https://github.com/baianat/base.extensions/tree/master/slider) 17 | * [Switcher](https://github.com/baianat/base.extensions/tree/master/switcher) 18 | * [Table](https://github.com/baianat/base.extensions/tree/master/table) 19 | 20 | ## License 21 | 22 | [MIT](http://opensource.org/licenses/MIT) 23 | 24 | Copyright (c) 2017 [Baianat](http://baianat.com) 25 | -------------------------------------------------------------------------------- /scripts/styles.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const chalk = require('chalk'); 3 | const stylus = require('stylus'); 4 | const uglifycss = require('uglifycss'); 5 | const autoprefixer = require('autoprefixer-stylus'); 6 | const mkdirpNode = require('mkdirp'); 7 | 8 | const { promisify } = require('util'); 9 | 10 | const mkdirp = promisify(mkdirpNode); 11 | const isProduction = process.env.MODE === 'production'; 12 | 13 | async function buildStyles () { 14 | console.log(chalk.cyan(`📦 Generating Stylesheets...`)); 15 | const app = fs.readFileSync(`blexar.styl`, 'utf8'); 16 | await mkdirp('dist'); 17 | stylusToCSS(app); 18 | } 19 | 20 | function stylusToCSS (styl) { 21 | stylus(styl) 22 | .use(autoprefixer({ browsers: ['last 5 version'] })) 23 | .render((err, css) => { 24 | if (err) { 25 | throw err; 26 | } 27 | 28 | console.log(`${chalk.green('👍 blexar.css')}`); 29 | fs.writeFileSync('dist/blexar.css', css); 30 | 31 | if (!isProduction) return; 32 | const uglifiedCss = uglifycss.processString(css); 33 | fs.writeFileSync('dist/blexar.min.css', uglifiedCss); 34 | }); 35 | } 36 | 37 | module.exports = { buildStyles }; 38 | 39 | buildStyles(); 40 | -------------------------------------------------------------------------------- /src/components/progress.styl: -------------------------------------------------------------------------------- 1 | .progress 2 | position: relative 3 | height: 1.2em 4 | width: 100% 5 | background-color: $light 6 | border-radius: 10em 7 | margin-bottom: 2em 8 | font-size: $font-tiny 9 | 10 | .progress-icon 11 | position: relative 12 | display: flex 13 | justify-content: center 14 | align-items: center 15 | z-index: 1 16 | border-radius: 10em 17 | border: 2px solid $white 18 | padding: $padding 19 | width: 3em 20 | height: 3em 21 | transform: translateY(-0.9em) 22 | // generate color modifiers 23 | for color in $modifiers-color 24 | $accent = lookup('$' + color) 25 | $text = isLight(color) ? $black : $white 26 | &.is-{color} 27 | background: $accent 28 | color: $text 29 | _icon-color: $text 30 | .progress-bar 31 | position: absolute 32 | top: 0 33 | {$dir-start}: 0 34 | display: flex 35 | align-items: center 36 | justify-content: center 37 | height: 100% 38 | border-radius: 10em 39 | background-color: $primary 40 | color: $white 41 | 42 | // generate color modifiers 43 | for color in $modifiers-color 44 | $accent = lookup('$' + color) 45 | $text = isLight(color) ? $black : $white 46 | &.is-{color} 47 | background: $accent 48 | color: $text -------------------------------------------------------------------------------- /src/components/input-group.styl: -------------------------------------------------------------------------------- 1 | .input-group 2 | display: flex 3 | margin-bottom: $margin 4 | >:not(:last-child) 5 | >.is-rounded:not(:last-child) 6 | &.is-rounded >:not(:last-child) 7 | border-top-{$dir-end}-radius: 0 8 | border-bottom-{$dir-end}-radius: 0 9 | >:not(:first-child) 10 | >.is-rounded:not(:first-child) 11 | &.is-rounded >:not(:first-child) 12 | border-top-{$dir-start}-radius: 0 13 | border-bottom-{$dir-start}-radius: 0 14 | >* 15 | >.button 16 | margin: 0 17 | .input + .input 18 | margin-{$dir-start}: -1px; 19 | 20 | 21 | // generate all modifiers 22 | for color in $modifiers-color 23 | &.is-{color} 24 | >.button 25 | @extends .button.is-{color} 26 | >.input 27 | @extends .input.is-{color} 28 | >.input-tag 29 | @extends .input-tag.is-{color} 30 | 31 | for size in $modifiers-size 32 | &.is-{size} 33 | >.button 34 | @extends .button.is-{size} 35 | >.input 36 | @extends .input.is-{size} 37 | >.input-tag 38 | @extends .input-tag.is-{size} 39 | 40 | for style in $modifiers-style 41 | &.is-{style} 42 | >.button 43 | @extends .button.is-{style} !optional 44 | >.input 45 | @extends .input.is-{style} !optional 46 | >.input-tag 47 | @extends .input-tag.is-{style} !optional -------------------------------------------------------------------------------- /src/components/label.styl: -------------------------------------------------------------------------------- 1 | .label 2 | display: inline-flex 3 | justify-content: center 4 | align-items: center 5 | overflow: hidden 6 | margin: 0 2px 7 | margin-bottom: $margin 8 | padding: 0.25em 0.5em 9 | min-width: 37px 10 | border-radius: $border-radius 11 | color: $black 12 | vertical-align: top 13 | font-weight: $weight-light 14 | line-height: 1 15 | _label-color: $gray $dark 16 | @extends $small 17 | 18 | img 19 | margin: -0.75em 20 | height: 2.5em 21 | vertical-align: top 22 | 23 | .icon 24 | height: 1em 25 | width: 1em 26 | 27 | .icon:first-child:not(:last-child) 28 | img:first-child:not(:last-child) 29 | margin-{$dir-end}: ($padding * 0.5) 30 | 31 | .icon:last-child:not(:first-child) 32 | img:last-child:not(:first-child) 33 | margin-{$dir-start}: ($padding * 0.5) 34 | 35 | // generate size modifiers 36 | generateSizes() 37 | 38 | // generate color modifiers 39 | for color in $modifiers-color 40 | $accentColor = lookup('$' + color) 41 | $textColor = isLight(color) ? $black : $white 42 | &.is-{color} 43 | _label-color: $accentColor $textColor 44 | 45 | &.is-rounded 46 | border-radius: 10em 47 | 48 | &.is-block 49 | display: flex 50 | 51 | &.is-float 52 | position: absolute 53 | top: 0 54 | margin: 0 55 | margin-top: $padding * -2 56 | {$dir-end}: 0 57 | margin-{$dir-end}: $padding * -2 58 | -------------------------------------------------------------------------------- /extensions/switcher/README.md: -------------------------------------------------------------------------------- 1 | # Switcher 2 | 3 | Switcher extension to add a dragging behavior to the Blexar framework switcher component. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | You can install switcher as part of all blexar's extensions. 10 | 11 | ```bash 12 | npm install @blexar/extensions 13 | 14 | # or using yarn 15 | yarn add @blexar/extensions 16 | ``` 17 | 18 | If you want the standalone version. 19 | 20 | ```bash 21 | npm install @blexar/switcher 22 | 23 | yarn add @blexar/switcher 24 | ``` 25 | 26 | ### Include necessary files 27 | 28 | ``` html 29 | 30 | 31 | 32 | 33 | 34 | ... 35 | 36 | 37 | ``` 38 | 39 | ### HTML Layout 40 | 41 | * `.switcher` 42 | * `.switcher-input` 43 | * `.switcher-body` 44 | * `.switcher-handle` 45 | 46 | ``` html 47 |
48 | 49 | 52 |
53 | ``` 54 | 55 | Once you include the script file, it will search for an element with `.switcher` class and adds the dragging behavior to it. 56 | 57 | ## License 58 | 59 | [MIT](http://opensource.org/licenses/MIT) 60 | 61 | Copyright (c) 2017 [Baianat](http://baianat.com) 62 | -------------------------------------------------------------------------------- /src/components/input-tag.styl: -------------------------------------------------------------------------------- 1 | .input-tag 2 | display: inline-flex 3 | padding: $padding ($padding * 1.5) 4 | border-width: $border 5 | border-style: solid 6 | border-radius: $border-radius 7 | vertical-align: top 8 | text-align: center 9 | border-color: $gray 10 | background-color: $gray 11 | line-height: $element-lineheight 12 | color: $dark 13 | white-space: nowrap 14 | _icon-color: $dark 15 | 16 | .icon:first-child:not(:last-child) 17 | margin-{$dir-end}: ($padding * 0.5) 18 | 19 | .icon:last-child:not(:first-child) 20 | margin-{$dir-start}: ($padding * 0.5) 21 | 22 | .icon:only-child 23 | margin: 0 ($padding * -0.5) 24 | 25 | >*:not(#blexar) 26 | margin: 0 27 | 28 | // generate size modifiers 29 | generateSizes() 30 | 31 | // generate color modifiers 32 | for color in $modifiers-color 33 | $color = lookup('$' + color) 34 | $textColor = isLight(color) ? $black : $white 35 | 36 | &.is-{color} 37 | border-color: $color 38 | background-color: $color 39 | color: $textColor 40 | _icon-color: $textColor 41 | 42 | &.is-rounded 43 | border-radius: 10em 44 | 45 | &.is-inverse 46 | background-color: transparent 47 | 48 | &.is-clean 49 | position: relative 50 | background-color: white 51 | _icon-color: $gray 52 | border-{$dir-end}: 0 53 | margin-{$dir-end}: -2px 54 | 55 | &.is-disabled 56 | opacity: 0.9 57 | cursor: not-allowed 58 | -------------------------------------------------------------------------------- /src/util/functions.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * check if the color name is a light color 3 | */ 4 | 5 | isLight(color) { 6 | if (color == 'white' || color == 'light' || color == 'gray' || color == 'warning') { 7 | return true; 8 | } 9 | return false; 10 | } 11 | 12 | /** 13 | * convert values to rem 14 | */ 15 | 16 | toRem(value) { 17 | u = unit(value); 18 | if (u is 'px') { 19 | return unit(value/16, 'rem'); 20 | } else { 21 | return unit(value, u); 22 | } 23 | } 24 | 25 | 26 | /** 27 | * get box shadow 28 | */ 29 | boxShadow() { 30 | return 0 6px 20px alpha($dark, 10%) 31 | } 32 | 33 | 34 | /** 35 | * Generate font sizes, based on equation 36 | * 37 | * F(n) = f(n - 1) + { floor((n - 2) / 4) + 1 } * 2 38 | * 39 | * | index | px | rem | 40 | * |-------|----|-------| 41 | * | 0 | 12 | 0.750 | 42 | * | 1 | 14 | 0.875 | 43 | * | 2 | 16 | 1 | 44 | * | 3 | 18 | 1.125 | 45 | * | 4 | 20 | 1.25 | 46 | * | 5 | 24 | 1.5 | 47 | * | 6 | 28 | 1.75 | 48 | * | 7 | 32 | 2 | 49 | * | 8 | 36 | 2.25 | 50 | * | 9 | 42 | 2.625 | 51 | * | 10 | 48 | 3 | 52 | * | 11 | 54 | 3.375 | 53 | * | 12 | 60 | 3.75 | 54 | * | 13 | 68 | 4.25 | 55 | * | 14 | 76 | 4.75 | 56 | * 57 | */ 58 | 59 | generateFontSizes() { 60 | current = 12; 61 | sizes = (); 62 | max = 16; 63 | for $n in (1...max) { 64 | increas = (floor(($n - 2) / 4) + 1) * 2 65 | current = current + increas; 66 | px = unit(current, 'px'); 67 | rem = toRem(px); 68 | push(sizes, rem); 69 | } 70 | return sizes; 71 | } 72 | -------------------------------------------------------------------------------- /src/components/accordion.styl: -------------------------------------------------------------------------------- 1 | .accordion 2 | margin: 0 3 | margin-bottom: $margin 4 | padding: 0 5 | max-width: 100% 6 | border-radius: $border-radius 7 | list-style: none 8 | 9 | &.is-clean 10 | margin-top: $margin 11 | 12 | &-item 13 | position: relative 14 | padding: $padding 15 | border-radius: $border-radius 16 | background-color: $white 17 | color: $black 18 | border: $border solid $gray 19 | 20 | &:not(:last-child) 21 | margin-bottom: 10px 22 | 23 | &.is-active 24 | >.accordion-title 25 | color: $primary 26 | >.accordion-icon 27 | transform: rotate(135deg) 28 | 29 | .is-clean & 30 | margin-bottom: 0 31 | border: 0 32 | 33 | &-body 34 | overflow: hidden 35 | margin: 0 36 | height: 0 37 | transition: $transition-time 38 | transition-timing-function: cubic-bezier(0, 0, 0.3, 1) 39 | @extends $normal 40 | 41 | .is-active > & 42 | margin-top: $margin 43 | height: auto 44 | 45 | &-list 46 | margin: 0 0 0 $margin 47 | padding: 0 48 | list-style: none 49 | 50 | li 51 | padding: $padding-px 52 | 53 | a 54 | color: $black 55 | text-decoration: none 56 | 57 | &:hover, 58 | &.is-active 59 | color: $primary 60 | 61 | &-title 62 | position: relative 63 | display: block 64 | width: 100% 65 | cursor: pointer 66 | text-decoration: none 67 | user-select: none 68 | color: $slategray 69 | @extend $normal 70 | &:hover 71 | color: $primary 72 | 73 | .accordion 74 | margin-bottom: 0 75 | -------------------------------------------------------------------------------- /scripts/extensions.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const uglify = require('uglify-js').minify; 4 | const chalk = require('chalk'); 5 | const mkdirpNode = require('mkdirp'); 6 | 7 | const { rollup } = require('rollup'); 8 | const { script, extensions } = require('./config'); 9 | const { promisify } = require('util'); 10 | 11 | const mkdirp = promisify(mkdirpNode); 12 | const isProduction = process.env.MODE === 'production'; 13 | 14 | async function buildScripts (format, ext) { 15 | console.log(chalk.cyan(`📦 Generating ${format} ${ext}...`)); 16 | 17 | // get the rollup bundle. 18 | const bundle = await rollup({ 19 | input: `extensions/${ext}/src/${ext}.js`, 20 | ...script.inputOptions 21 | }); 22 | 23 | // pass the desired output config 24 | const { code } = await bundle.generate({ 25 | format: format, 26 | name: `${ext.charAt(0).toUpperCase()}${ext.slice(1)}`, 27 | banner: script.banner 28 | }); 29 | 30 | let fileName = `${ext}${format === 'es' ? '.esm' : ''}.js`; 31 | let filePath = path.join(`extensions/${ext}/dist/`, fileName); 32 | 33 | await mkdirp(`extensions/${ext}/dist/`); 34 | // write the un-minified code. 35 | fs.writeFileSync(filePath, code); 36 | console.log(chalk.green(`👍 ${fileName}`)); 37 | 38 | // write the minified code. 39 | if (!isProduction || format !== 'umd') return; 40 | filePath = path.join(`extensions/${ext}/dist/`, `${ext}.min.js`); 41 | fs.writeFileSync(filePath, uglify(code, script.uglifyOptions).code); 42 | } 43 | 44 | extensions.forEach(ext => { 45 | buildScripts('es', ext); 46 | buildScripts('umd', ext); 47 | }); 48 | 49 | module.exports = { buildScripts }; 50 | -------------------------------------------------------------------------------- /extensions/datepicker/README.md: -------------------------------------------------------------------------------- 1 | # Datepicker(WIP) 2 | 3 | Datepicker extension for Blexar framework. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | You can install datepicker as part of all blexar's extensions. 10 | 11 | ```bash 12 | npm install @blexar/extensions 13 | 14 | # or using yarn 15 | yarn add @blexar/base.extensions 16 | ``` 17 | 18 | If you want the standalone version. 19 | 20 | ```bash 21 | npm install @blexar/datepicker 22 | 23 | yarn add @blexar/datepicker 24 | ``` 25 | 26 | ### Include necessary files 27 | 28 | ``` html 29 | 30 | 31 | 32 | 33 | 34 | ... 35 | 36 | 37 | ``` 38 | 39 | ### HTML Layout 40 | 41 | You need an input element to output the date value on it. 42 | 43 | ``` html 44 | 45 | ``` 46 | 47 | ### Create the Datepicker 48 | 49 | You now need to create a new `Datepicker` instance. 50 | 51 | ```js 52 | const myDate = new Datepicker('#myDate'[, settings ]); 53 | ``` 54 | 55 | | OPTION | DEFAULT | DESCRIPTION | 56 | | ------ | ------- | ----------- | 57 | | `dateFormat` | 'dd/MM/yyyy' | string that represents the output date format | 58 | | `days` | ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] | array of days name to display in calender | 59 | | `months` | ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] | array of months names to display in months selector | 60 | 61 | ## License 62 | 63 | [MIT](http://opensource.org/licenses/MIT) 64 | 65 | Copyright (c) 2017 [Baianat](http://baianat.com) 66 | -------------------------------------------------------------------------------- /src/core/defaults.styl: -------------------------------------------------------------------------------- 1 | ::selection 2 | background: $primary 3 | color: $white 4 | 5 | * 6 | box-sizing: border-box 7 | 8 | ::placeholder 9 | color: $dark 10 | opacity: 0.3 11 | 12 | &:focus 13 | outline: 0 14 | 15 | html 16 | direction: $dir 17 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' 18 | font-weight: $font-weight-normal 19 | 20 | a 21 | color: $link 22 | cursor: pointer 23 | text-decoration: none 24 | 25 | &:hover 26 | color: $link-hover 27 | 28 | img 29 | max-width: 100% 30 | height: auto 31 | 32 | li + li 33 | margin-top: 0.25em 34 | 35 | p, dl, ol, ul, blockquote, pre 36 | font-size: 1em 37 | 38 | &:not(:last-child) 39 | margin-bottom: 1em 40 | 41 | blockquote 42 | border-{$dir-start}: 0.5em solid $primary 43 | padding: $padding 44 | margin: 0 45 | 46 | ol 47 | list-style: decimal outside 48 | margin-{$dir-start}: 1em 49 | margin-top: 1em 50 | padding-{$dir-start}: 1em 51 | 52 | ul 53 | list-style: disc outside 54 | margin-{$dir-start}: 1em 55 | margin-top: 1em 56 | padding-{$dir-start}: 1em 57 | 58 | ul 59 | list-style-type: circle 60 | margin-top: 0.5em 61 | 62 | ul 63 | list-style-type: square 64 | 65 | dd 66 | margin-{$dir-start}: 2em 67 | 68 | figure 69 | margin-left: 2em 70 | margin-right: 2em 71 | text-align: center 72 | 73 | &:not(:first-child) 74 | margin-top: 2em 75 | 76 | &:not(:last-child) 77 | margin-bottom: 2em 78 | 79 | img 80 | display: inline-block 81 | 82 | figcaption 83 | font-style: italic 84 | 85 | pre 86 | overflow-x: auto 87 | padding: $padding 88 | white-space: pre 89 | word-wrap: normal -------------------------------------------------------------------------------- /src/components/checkbox.styl: -------------------------------------------------------------------------------- 1 | .checkbox 2 | margin: 0 0 $margin 0 3 | display: flex 4 | align-items: center 5 | cursor: pointer 6 | &.is-inline 7 | display: inline-flex 8 | margin-{$dir-end}: 0.8em 9 | &.is-disabled 10 | &[disabled] 11 | opacity: 0.6 12 | pointer-events: none 13 | cursor: not-allowed 14 | 15 | generateSizes() 16 | 17 | .checkbox-input 18 | display: inline-flex 19 | justify-content: center 20 | align-items: center 21 | padding: 0 22 | width: 1.3em 23 | height: 1.3em 24 | border: $border solid $gray 25 | border-radius: $border-radius 26 | background-color: $white 27 | cursor: pointer 28 | outline: none 29 | appearance: none 30 | -webkit-appearance: none 31 | -moz-appearance: none 32 | &:after 33 | display: block 34 | opacity: 0 35 | width: 0.2em 36 | height: 0.5em 37 | border: solid $white 38 | border-width: 0 0.13em 0.13em 0 39 | content: '' 40 | transform: translate3d(0, -0.1em, 0) rotate(45deg) 41 | &:focus 42 | border-color: $primary 43 | box-shadow: 0 0 0 $outline alpha($primary, $outline-opacity) 44 | &:checked 45 | &.is-checked 46 | background-color: $primary 47 | border-color: $primary 48 | &:after 49 | opacity: 1 50 | &:indeterminate 51 | &.is-indeterminate 52 | background-color: $primary 53 | border-color: $primary 54 | &:after 55 | width: 0.5em 56 | height: 0.13em 57 | transform: rotate(0) 58 | border-width: 0 0 0.13em 59 | opacity: 1 60 | &.is-disabled 61 | &[disabled] 62 | opacity: 0.6 63 | pointer-events: none 64 | cursor: not-allowed 65 | 66 | .checkbox-label 67 | vertical-align: middle 68 | margin-{$dir-start}: 0.4em 69 | 70 | 71 | input.checkbox 72 | @extends .checkbox-input -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Blexar 2 | 3 | **A solid base to establish your favorite websites with user experience in mind.** 4 | 5 | Inspired by the user's own experience needs, we decided to implement a design system to serve as a solid basis for very simple, yet elegant websites to deliver a complexity-free environment. 6 | 7 | ## Main Features 8 | 9 | * Works well with SVG out of the box. 10 | * Offers some of the simplistic UI elements out there. 11 | * Intelligent grid system based on Flex-box. 12 | * Built using Stylus preprocessor. 13 | * User-friendly documentation with editable code snippets. 14 | 15 | ## Getting Started 16 | 17 | ### Installation 18 | 19 | Using npm 20 | 21 | ```bash 22 | npm install blexar --save 23 | #or using yarn 24 | yarn add blexar 25 | ``` 26 | 27 | ### HTML Layout 28 | 29 | ```html 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ... 42 | 43 | 44 | 45 | ``` 46 | 47 | ### Webpack Configuration 48 | 49 | Add the following rule to the Webpack configuration file 50 | 51 | ```javascript 52 | { 53 | test: /.styl$/, 54 | loader: 'style-loader!css-loader!stylus-loader?resolve url' 55 | } 56 | ``` 57 | 58 | ### Working with styles 59 | 60 | In your main styling file `app.styl`, before including the Base main file, make sure to add the needed variables, according to your customization preferences. 61 | 62 | ```CSS 63 | $margin = 2px 64 | $red = #E13C31 65 | @import "~blexar" 66 | ``` 67 | 68 | ## License 69 | 70 | [MIT](http://opensource.org/licenses/MIT) 71 | 72 | Copyright (c) 2019 [Baianat](http://baianat.com) 73 | -------------------------------------------------------------------------------- /src/components/buttons.styl: -------------------------------------------------------------------------------- 1 | .buttons 2 | display: inline-flex 3 | flex-wrap: wrap 4 | align-items: center 5 | margin-bottom: $margin 6 | 7 | >:not(:last-child), >.is-rounded:not(:last-child), &.is-rounded >:not(:last-child) 8 | border-top-{$dir-end}-radius: 0 9 | border-bottom-{$dir-end}-radius: 0 10 | 11 | >:not(:first-child), >.is-rounded:not(:first-child), &.is-rounded >:not(:first-child) 12 | border-top-{$dir-start}-radius: 0 13 | border-bottom-{$dir-start}-radius: 0 14 | 15 | >.button 16 | margin-bottom: 0 17 | margin-{$dir-end}: 0 18 | 19 | .button + .button 20 | border-{$dir-start}: 0 21 | margin-{$dir-start}: 0 22 | 23 | &.is-block 24 | flex-wrap: nowrap 25 | 26 | &.is-gradient 27 | border-radius: $border-radius 28 | 29 | >.button 30 | background-color: transparent 31 | border: 0 32 | 33 | &.is-rounded 34 | border-radius: 10em 35 | 36 | // generate all modifiers 37 | for color in $modifiers-color 38 | &.is-{color} 39 | >.button 40 | @extend .button.is-{color} 41 | 42 | &.is-{color}.is-outlined 43 | >.button 44 | @extend .button.is-{color}.is-outlined 45 | 46 | &.is-{color}.is-bright 47 | >.button 48 | @extend .button.is-{color}.is-bright 49 | 50 | for color in $modifiers-color-grad 51 | $grad = lookup('$grad-' + color) 52 | 53 | &.is-{color}.is-gradient 54 | background-image: linear-gradient($grad-direction, $grad[0], $grad[1]) 55 | 56 | for size in $modifiers-size 57 | &.is-{size} 58 | >.button 59 | @extend .button.is-{size} 60 | 61 | for style in $modifiers-style 62 | &.is-{style} 63 | >.button 64 | @extend .button.is-{style} 65 | 66 | &[disabled] 67 | >.button 68 | @extend .button[disabled] 69 | -------------------------------------------------------------------------------- /src/grid/grid.styl: -------------------------------------------------------------------------------- 1 | .grid 2 | position: relative 3 | display: flex 4 | flex-wrap: wrap 5 | margin-right: $gutter * -1 6 | margin-left: $gutter * -1 7 | width: auto 8 | 9 | &[class*='is-tablet-'], &[class*='is-desktop-'], &[class*='is-widescreen-'], &[class*='is-ultrawide-'] 10 | >.column:not([class*='is-']) 11 | @extends .column[class*='is-tablet-'] 12 | 13 | for $n in (1 .. $columns) 14 | &.is-{$n}, &.is-mobile-{$n} 15 | >.column:not([class*='is-']) 16 | @extends .column.is-{$n} 17 | 18 | +tablet() 19 | for $n in (1 .. $columns) 20 | &.is-tablet-{$n} 21 | >.column:not([class*='is-']) 22 | @extends .column.is-tablet-{$n} 23 | 24 | +desktop() 25 | for $n in (1 .. $columns) 26 | &.is-desktop-{$n} 27 | >.column:not([class*='is-']) 28 | @extends .column.is-desktop-{$n} 29 | 30 | +widescreen() 31 | for $n in (1 .. $columns) 32 | &.is-widescreen-{$n} 33 | >.column:not([class*='is-']) 34 | @extends .column.is-widescreen-{$n} 35 | 36 | +ultrawide() 37 | for $n in (1 .. $columns) 38 | &.is-ultrawide-{$n} 39 | >.column:not([class*='is-']) 40 | @extends .column.is-ultrawide-{$n} 41 | 42 | &.is-center 43 | justify-content: center 44 | 45 | &.is-end 46 | justify-content: flex-end 47 | 48 | &.is-start 49 | justify-content: flex-start 50 | 51 | &.is-middle 52 | align-items: center 53 | 54 | &.is-top 55 | align-items: flex-start 56 | 57 | &.is-bottom 58 | align-items: flex-end 59 | 60 | &.is-vertical 61 | flex-direction: column 62 | align-items: flex-start 63 | 64 | &.is-shrink 65 | >.column:not([class*='is-']) 66 | flex: 0 0 auto 67 | 68 | &.is-fit 69 | margin-right: 0 70 | margin-left: 0 71 | 72 | >.column 73 | padding: 0 74 | -------------------------------------------------------------------------------- /src/components/navbar.styl: -------------------------------------------------------------------------------- 1 | .navbar 2 | display: flex 3 | margin: 0 4 | width: 100% 5 | padding: 0 ($padding * 2) 6 | background-color: $white 7 | font-weight: $font-weight-semi-bold 8 | @extend $normal 9 | 10 | &.is-gradient 11 | background-image: linear-gradient(90deg, $grad-primary) 12 | color: $white 13 | 14 | &.is-fixed 15 | position: fixed 16 | z-index: 9999 17 | top: 0 18 | left: 0 19 | right: 0 20 | transition: 0.4s 21 | 22 | &.is-inverse 23 | background-color: $black 24 | 25 | &.is-hidden 26 | transform: translate3d(0, -100%, 0) 27 | // reset nested elements 28 | 29 | 30 | .navbar-brand 31 | display: flex 32 | align-items: center 33 | .navbar-start, 34 | .navbar-end 35 | display: flex 36 | 37 | .navbar-brand 38 | margin-{$dir-end}: $margin 39 | img 40 | max-height: 40px 41 | display: block 42 | &.is-white 43 | filter: brightness(0) invert(1) 44 | fill: $white 45 | 46 | .navbar-start, 47 | .navbar-end 48 | flex: 1 49 | .navbar-end 50 | justify-content: flex-end 51 | .navbar-item 52 | display: flex 53 | justify-content: center 54 | align-items: center 55 | padding: 0 (2 * $padding) 56 | min-height: 50px 57 | color: $black 58 | text-decoration: none 59 | white-space: nowrap 60 | cursor: pointer 61 | _icon-color: $black 62 | @extends $normal 63 | .navbar-item 64 | padding: 0 65 | 66 | &.dropdown 67 | height: auto 68 | 69 | &:hover, &:focus 70 | color: $primary 71 | _icon-color: $primary 72 | 73 | .navbar.is-inverse &, 74 | .navbar.is-gradient & 75 | color: $white 76 | _icon-color: $white 77 | 78 | &:hover, &:focus 79 | color: $primary 80 | _icon-color: $primary 81 | 82 | &.is-active 83 | background-color: alpha($black, 8%) 84 | 85 | &:hover 86 | background-color: alpha($white, 8%) 87 | 88 | .button 89 | margin-bottom: 0 -------------------------------------------------------------------------------- /src/components/switcher.styl: -------------------------------------------------------------------------------- 1 | .switcher 2 | display: inline-flex 3 | margin: $margin * 0.5 4 | vertical-align: middle 5 | 6 | &-input 7 | display: none 8 | 9 | &:checked 10 | + .switcher-body 11 | background-color: $primary 12 | padding-{$dir-start}: 0.5em 13 | padding-{$dir-end}: 1.3em 14 | 15 | .switcher-handle 16 | {$dir-start}: calc(100% - 1.3em) 17 | 18 | .switcher-true 19 | max-width: 40em 20 | opacity: 1 21 | 22 | .switcher-false 23 | max-width: 0em 24 | opacity: 0 25 | 26 | &[disabled] 27 | opacity: 0.6 28 | cursor: not-allowed 29 | 30 | + .switcher-body 31 | opacity: 0.6 32 | cursor: not-allowed 33 | 34 | &-body 35 | position: relative 36 | display: inline-flex 37 | padding: 0 38 | padding-{$dir-start}: 1.3em 39 | padding-{$dir-end}: 0.5em 40 | min-width: 2.6em 41 | height: 1.3em 42 | background-color: $gray 43 | cursor: pointer 44 | transition: 0.3s 45 | justify-content: center 46 | align-items: center 47 | color: $white 48 | user-select: none 49 | border-radius: 1em 50 | p 51 | font-size: 0.8em 52 | 53 | &-true 54 | max-width: 0em 55 | opacity: 0 56 | 57 | &-false 58 | max-width: 40em 59 | opacity: 1 60 | 61 | &-handle 62 | position: absolute 63 | {$dir-start}: 0 64 | margin: 0.25em 65 | top: 0 66 | display: block 67 | width: 0.8em 68 | height: 0.8em 69 | background-color: $white 70 | content: '' 71 | transition: 0.3s 72 | border-radius: 1em 73 | 74 | &.is-dragging 75 | transition: 0 76 | 77 | &.is-disabled, &[disabled] 78 | cursor: not-allowed 79 | pointer-events: none 80 | opacity: 0.6 81 | 82 | .switcher-input 83 | cursor: not-allowed 84 | 85 | generateSizes() -------------------------------------------------------------------------------- /extensions/accordion/README.md: -------------------------------------------------------------------------------- 1 | # Accordion 2 | 3 | Accordion extension for Blexar framework. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | You can install accordion as part of all blexar's extensions 10 | 11 | ```bash 12 | npm install @blexar/extensions 13 | 14 | # or using yarn 15 | yarn add @blexar/extensions 16 | ``` 17 | 18 | If you want the standalone version 19 | 20 | ```bash 21 | npm install @blexar/accordion 22 | 23 | # or using yarn 24 | yarn add @blexar/accordion 25 | ``` 26 | 27 | ### Include necessary files 28 | 29 | ``` html 30 | 31 | 32 | 33 | 34 | 35 | ... 36 | 37 | 38 | ``` 39 | 40 | ### HTML Layout 41 | 42 | * `.accordion` 43 | * `.accordion-item` 44 | * `.accordion-title` 45 | * `.accordion-body` 46 | * `.accordion-item` 47 | * ... 48 | 49 | ``` html 50 | 68 | ``` 69 | 70 | If you want the clean version of accordion add `.is-clean` class to main div 71 | 72 | ```html 73 | 76 | ``` 77 | 78 | ### Make it work 79 | 80 | One last step is to call create new accordion 81 | 82 | ```js 83 | let myAccordion = new Accordion('#myAccordion'); 84 | ``` 85 | 86 | ## License 87 | 88 | [MIT](http://opensource.org/licenses/MIT) 89 | 90 | Copyright (c) 2017 [Baianat](http://baianat.com) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@blexar/framework", 3 | "version": "0.0.33", 4 | "description": "CSS framework to establish your favorite websites in mints, with user experience in mind.", 5 | "author": "Abdelrahman Ismail ", 6 | "main": "dist/blexar.css", 7 | "style": "dist/blexar.css", 8 | "repository": "https://github.com/baianat/blexar", 9 | "scripts": { 10 | "lint": "eslint ./src --fix", 11 | "build:extensions": "MODE=production node scripts/extensions", 12 | "build:styles": "MODE=production node scripts/styles", 13 | "build": "npm run build:styles && npm run build:extensions", 14 | "dev": "MODE=dev node scripts/watcher" 15 | }, 16 | "dependencies": { 17 | "color-fns": "^0.0.7", 18 | "date-fns": "^2.0.0-alpha.16" 19 | }, 20 | "devDependencies": { 21 | "autoprefixer-stylus": "^0.14.0", 22 | "babel-core": "^6.26.0", 23 | "babel-plugin-external-helpers": "^6.22.0", 24 | "babel-plugin-transform-async-to-generator": "^6.24.1", 25 | "babel-plugin-transform-class-properties": "^6.24.1", 26 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 27 | "babel-preset-env": "^1.6.1", 28 | "browser-sync": "^2.23.6", 29 | "chalk": "^2.3.2", 30 | "eslint-config-standard": "^12.0.0", 31 | "eslint-plugin-import": "^2.14.0", 32 | "eslint-plugin-node": "^7.0.1", 33 | "eslint-plugin-promise": "^4.0.0", 34 | "eslint-plugin-standard": "^4.0.0", 35 | "mkdirp": "^0.5.1", 36 | "rollup": "^0.57.1", 37 | "rollup-plugin-babel": "^3.0.3", 38 | "rollup-plugin-json": "^2.3.0", 39 | "rollup-plugin-node-resolve": "^3.3.0", 40 | "rollup-plugin-replace": "^2.0.0", 41 | "stylus": "^0.54.5", 42 | "uglify-js": "^3.3.21", 43 | "uglifycss": "0.0.29", 44 | "util": "^0.11.0" 45 | }, 46 | "license": "MIT", 47 | "keywords": [ 48 | "CSS", 49 | "framework" 50 | ], 51 | "maintainers": [ 52 | { 53 | "name": "Abdelrahman3D", 54 | "email": "abdelrahman3d@gmail.com" 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /src/components/modal.styl: -------------------------------------------------------------------------------- 1 | .modal 2 | position: relative 3 | display: flex 4 | flex-direction: column 5 | justify-content: center 6 | align-items: stretch 7 | padding: $modal-spacing 8 | width: 100% 9 | border: 0 10 | border-radius: $border-radius-large 11 | background-color: $white 12 | max-width: 500px 13 | margin-left: auto 14 | margin-right: auto 15 | margin-bottom: $modal-spacing 16 | box-shadow: boxShadow(large) 17 | @extend $normal 18 | 19 | for color in $modifiers-color 20 | $accentColor = lookup('$' + color) 21 | $textColor = isLight(color) ? $dark : $accentColor 22 | 23 | &.is-{color} 24 | _modal-color: $accentColor $textColor 25 | 26 | &.is-outlined 27 | border-width: $border 28 | border-style: solid 29 | background-color: alpha($white, 10%) 30 | 31 | &.is-fit 32 | padding: 1em 33 | 34 | &.is-rounded 35 | border-radius: 10em 36 | 37 | .modal-header 38 | position: relative 39 | margin-bottom: $modal-spacing 40 | 41 | .modal-title 42 | margin: 0 43 | 44 | .modal-body 45 | display: flex 46 | position: relative 47 | padding: 0 48 | 49 | * 50 | margin-top: 0 51 | margin-bottom: 0 52 | 53 | .modal-icon 54 | margin-{$dir-end}: $modal-spacing 55 | 56 | .modal-footer 57 | display: flex 58 | margin-top: $modal-spacing 59 | 60 | >* 61 | margin-bottom: 0 62 | 63 | .modal-dismiss 64 | position: absolute 65 | top: 0 66 | padding: 1em 67 | border: 0 68 | background-color: transparent 69 | {$dir-end}: 0 70 | cursor: pointer 71 | _icon-color: inherit 72 | 73 | &:focus 74 | outline: none 75 | 76 | &:hover 77 | _icon-color: $primary 78 | 79 | .modal-container 80 | position: fixed 81 | top: 0 82 | right: 0 83 | left: 0 84 | display: flex 85 | justify-content: center 86 | align-items: center 87 | width: 100% 88 | height: 100vh 89 | background-color: alpha($black, 10%) 90 | z-index: 999 91 | 92 | &.is-hidden 93 | display: none 94 | 95 | &.is-visable 96 | display: flex 97 | -------------------------------------------------------------------------------- /src/util/variables.styl: -------------------------------------------------------------------------------- 1 | $font-size = generateFontSizes() 2 | /** 3 | * elemets sizes 4 | */ 5 | $size-tiny ?= $font-size[0] 6 | $size-small ?= $font-size[1] 7 | $size-normal ?= $font-size[2] 8 | $size-large ?= $font-size[3] 9 | $size-massive ?= $font-size[4] 10 | /** 11 | * typography 12 | */ 13 | $font-tiny ?= $font-size[0] 14 | $font-small ?= $font-size[1] 15 | $font-normal ?= $font-size[2] 16 | $font-large ?= $font-size[3] 17 | $font-massive ?= $font-size[4] 18 | $lineheight ?= 1.1875 19 | $font-weight-light ?= 300 20 | $font-weight-normal ?= 400 21 | $font-weight-medium ?= 500 22 | $font-weight-semi-bold ?= 600 23 | $font-weight-bold ?= 700 24 | $font-weight-heavy ?= 800 25 | $font-weight-super ?= 900 26 | /** 27 | * Device Breakpoint 28 | */ 29 | $mobile ?= 0 30 | $tablet ?= 768px 31 | $desktop ?= 991px 32 | $widescreen ?= 1360px 33 | $ultrawide ?= 1920px 34 | /** 35 | * grid 36 | */ 37 | $columns ?= 12 38 | $dir ?= ltr 39 | $dir-start ?= $dir == 'ltr' ? left : right 40 | $dir-end ?= $dir == 'ltr' ? right : left 41 | $gutter ?= toRem(10px) 42 | $gutter-full ?= 8vw 43 | $container-mobile ?= 100% 44 | $container-tablet ?= $tablet - (22 * 2) 45 | $container-desktop ?= $desktop - (22 * 3) 46 | $container-widescreen ?= $widescreen - (22 * 4) 47 | $container-ultrawide ?= $ultrawide - (22 * 5) 48 | $round-digits ?= 4 49 | /* 50 | * style 51 | */ 52 | $margin ?= 0.5em 53 | $padding ?= 0.5em 54 | $padding-px ?= 20px 55 | $modal-spacing ?= 2em 56 | $border-radius ?= 4px 57 | $border-radius-large ?= 8px 58 | $border ?= 1px 59 | $outline ?= 3px 60 | $outline-opacity ?= 25% 61 | $element-lineheight ?= 1.3 62 | /** 63 | * animation 64 | */ 65 | $transition-time ?= 0.2s 66 | $transition-function ?= ease-in-out 67 | /** 68 | * modifiers 69 | */ 70 | $modifiers-size ?= 'tiny' 'small' 'normal' 'large' 'massive' 71 | $modifiers-style ?= 'block' 'disabled' 'rounded' 'outlined' 'bright' 72 | $modifiers-color ?= 'primary' 'secondary' 'info' 'success' 'warning' 'danger' 'black' 'white' 'dark' 'light' 73 | $modifiers-color-grad ?= 'primary' 'secondary' 'info' 'success' 'warning' 'danger' -------------------------------------------------------------------------------- /extensions/modal/README.md: -------------------------------------------------------------------------------- 1 | # Dropdown 2 | 3 | Modal extension for Blexar framework. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | You can install modal as part of all blexar's extensions. 10 | 11 | ```bash 12 | npm install @blexar/extensions 13 | 14 | # or using yarn 15 | yarn add @blexar/extensions 16 | ``` 17 | 18 | If you want the standalone version. 19 | 20 | ```bash 21 | npm install @blexar/modal 22 | 23 | yarn add @blexar/modal 24 | ``` 25 | 26 | ### Include necessary files 27 | 28 | ``` html 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ... 38 | 39 | 40 | ``` 41 | 42 | ### HTML Layout 43 | 44 | * `.modal-container` 45 | * `.modal` 46 | * `.modal-header` 47 | * `.modal-dismiss` 48 | * `.modal-title` 49 | * `.modal-body` 50 | * `.modal-icon` 51 | * `.modal-footer` 52 | 53 | ``` html 54 | 55 | 56 | 73 | ``` 74 | 75 | ### JavaScript 76 | 77 | Note: you can add `[data-base-modal]` attribute to the button element and its value will serve as a CSS selector for the `.modal` itself 78 | 79 | ```js 80 | const newModal = new Modal('#modalSelector', '#buttonSelector'); 81 | ``` 82 | 83 | ## License 84 | 85 | [MIT](http://opensource.org/licenses/MIT) 86 | 87 | Copyright (c) 2017 [Baianat](http://baianat.com) 88 | -------------------------------------------------------------------------------- /extensions/dropdown/src/dropdown.js: -------------------------------------------------------------------------------- 1 | import select from '../../_utils/select'; 2 | import isElementClosest from '../../_utils/isElementClosest'; 3 | 4 | /** 5 | * modal class 6 | */ 7 | export default class Dropdown { 8 | static defaults = { 9 | menuVisible: 'is-visible', 10 | menuHidden: 'is-hidden', 11 | elementActive: 'is-active', 12 | hideWhenClickOut: false 13 | } 14 | constructor (selector, menu = null, settings) { 15 | this.el = select(selector); 16 | this.menu = select(menu); 17 | this.settings = { 18 | ...Dropdown.defaults, 19 | ...settings 20 | }; 21 | this.init(); 22 | } 23 | 24 | /** 25 | * add event listeners to the modal elements 26 | * @param {HTMLElement} button 27 | * @param {HTMLElement} element 28 | */ 29 | init () { 30 | this.hide(); 31 | this.initEvents(); 32 | } 33 | 34 | initEvents () { 35 | this.el.addEventListener('click', this.toggleVisibility.bind(this)); 36 | } 37 | 38 | toggleVisibility (event) { 39 | if (this.isVisible && !isElementClosest(event.target, this.menu)) { 40 | this.hide(); 41 | return; 42 | } 43 | this.show(event); 44 | } 45 | 46 | show () { 47 | this.isVisible = true; 48 | this.menu.classList.add(this.settings.menuVisible); 49 | this.menu.classList.remove(this.settings.menuHidden); 50 | this.menu.setAttribute('aria-hidden', 'false'); 51 | this.el.classList.add(this.settings.elementActive); 52 | 53 | if (this.settings.hideWhenClickOut) { 54 | this.tempHandler = this.whenClickOut.bind(this); 55 | document.addEventListener('click', this.tempHandler); 56 | } 57 | } 58 | 59 | hide () { 60 | this.isVisible = false; 61 | this.menu.classList.remove(this.settings.menuVisible); 62 | this.menu.classList.add(this.settings.menuHidden); 63 | this.menu.setAttribute('aria-hidden', 'true'); 64 | this.el.classList.remove(this.settings.elementActive); 65 | 66 | document.removeEventListener('click', this.tempHandler); 67 | } 68 | 69 | whenClickOut (event) { 70 | if (!isElementClosest(event.target, this.el) && 71 | !isElementClosest(event.target, this.menu) 72 | ) { 73 | this.hide(); 74 | } 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /extensions/accordion/src/accordion.js: -------------------------------------------------------------------------------- 1 | import async from '../../_utils/async'; 2 | import select from '../../_utils/select'; 3 | 4 | /** 5 | * accordion class 6 | */ 7 | export default class Accordion { 8 | static defaults = { 9 | autoClose: true 10 | } 11 | 12 | constructor(selector, settings) { 13 | this.el = select(selector); 14 | this.settings = { 15 | ...Accordion.defaults, 16 | ...settings 17 | } 18 | this.init(); 19 | } 20 | 21 | /** 22 | * create new rang accordion from element 23 | */ 24 | init() { 25 | this.items = Array.from(this.el.querySelectorAll(':scope >.accordion-item')); 26 | this.activeItems = this.items.filter(item => item.classList.contains('is-active')); 27 | this.titles = this.items.map(item => item.querySelector('.accordion-title')); 28 | this.titles.forEach((title) => { 29 | title.addEventListener('click', () => this.update(title), false); 30 | }); 31 | } 32 | 33 | /** 34 | * update accordion states 35 | * @param {HTMLElement} title 36 | */ 37 | update(title) { 38 | const item = title.parentNode; 39 | if (this.activeItems.includes(item)) { 40 | this.collapse(item); 41 | return; 42 | } 43 | this.expand(item); 44 | } 45 | 46 | /** 47 | * collapse the open panel 48 | * @param {HTMLElement} item 49 | */ 50 | collapse(item) { 51 | this.activeItems.splice(this.activeItems.indexOf(item), 1); 52 | const body = item.querySelector('.accordion-body'); 53 | body.style.height = `${body.clientHeight}px`; 54 | async(() => { 55 | body.style.height = ''; 56 | item.classList.remove('is-active'); 57 | }); 58 | } 59 | 60 | /** 61 | * expand the close panel 62 | * @param {HTMLElement} item 63 | */ 64 | expand(item) { 65 | if (this.settings.autoClose) { 66 | const temp = this.activeItems.slice(0); 67 | temp.forEach(item => this.collapse(item)); 68 | } 69 | this.activeItems.push(item); 70 | const body = item.querySelector('.accordion-body'); 71 | item.classList.add('is-active'); 72 | const bodyHeight = body.clientHeight; 73 | body.style.height = 0; 74 | body.addEventListener('transitionend', () => body.style.height = ''); 75 | async(() => { 76 | body.style.height = `${bodyHeight}px`; 77 | }) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/components/slider.styl: -------------------------------------------------------------------------------- 1 | .slider 2 | position: relative 3 | display: flex 4 | align-items: center 5 | box-sizing: border-box 6 | margin-bottom: $margin 7 | 8 | &-input 9 | display: none 10 | width: auto 11 | max-width: 150px 12 | margin-bottom: 0 13 | @extend .input.is-tiny 14 | 15 | &-track 16 | position: relative 17 | flex: 1 18 | margin: 0.2em 19 | width: auto 20 | height: 0.3em 21 | background: $gray 22 | border-radius: $border-radius 23 | will-change: transfom 24 | 25 | &-handle 26 | position: relative 27 | position: absolute 28 | top: 0 29 | left: 0 30 | will-change: transform 31 | color: $black 32 | margin: -0.25em 0 0 -0.25em 33 | width: 0.8em 34 | height: 0.8em 35 | background-color: currentColor 36 | border-radius: 0.8em 37 | box-shadow: 0 1px 6px -2px alpha($black, 20%) 38 | border: 2px solid $white 39 | &-label 40 | position: absolute 41 | top: -3em 42 | left: 0.4em 43 | z-index: 999 44 | visibility: hidden 45 | padding: 6px 46 | min-width: 3em 47 | border-radius: $border-radius 48 | background-color: $black 49 | color: $white 50 | text-align: center 51 | font-size: $size-tiny 52 | line-height: 1em 53 | opacity: 0 54 | transform: translate(-50%, 0) 55 | white-space: nowrap 56 | 57 | &:before 58 | position: absolute 59 | bottom: -0.6em 60 | left: 50% 61 | display: block 62 | width: 0 63 | height: 0 64 | border-width: 0.6em 0.6em 0 0.6em 65 | border-style: solid 66 | border-color: $black transparent transparent transparent 67 | content: '' 68 | transform: translate3d(-50%, 0, 0) 69 | 70 | &-fill 71 | width: 100% 72 | height: 100% 73 | background-color: $gray 74 | transform-origin: left top 75 | 76 | &:hover, 77 | &.is-dragging 78 | .slider-label 79 | visibility: visible 80 | opacity: 1 81 | 82 | &.is-editable 83 | .slider-input 84 | display: block 85 | 86 | &.is-reverse 87 | flex-direction: row-reverse 88 | 89 | &.is-rounded 90 | .slider-handle, 91 | .slider-track, 92 | .slider-fill 93 | border-radius 10em 94 | generateSizes() -------------------------------------------------------------------------------- /src/grid/column.styl: -------------------------------------------------------------------------------- 1 | .column 2 | flex: 1 0 0 3 | padding-right: $gutter 4 | padding-left: $gutter 5 | 6 | &[class*='is-tablet-'], 7 | &[class*='is-desktop-'], 8 | &[class*='is-widescreen-'], 9 | &[class*='is-ultrawide-'] 10 | // we used flex basis auto to fix grid bug in ie 11 | flex: 0 0 auto 12 | // we used min-width with width property 13 | // to stop FireFox default behavoir 14 | // when content is bigger than column 15 | min-width: 100% 16 | width: 100% 17 | 18 | for $n in (0 .. $columns) 19 | &.is-{$n}, 20 | &.is-mobile-{$n} 21 | min-width: round($n / $columns * 100%, $round-digits) 22 | width: round($n / $columns * 100%, $round-digits) 23 | 24 | &.is-offset-{$n}, 25 | &.is-offset-mobile-{$n} 26 | margin-{$dir-start}: round($n / $columns * 100%, $round-digits) 27 | 28 | +tablet() 29 | for $n in (0 .. $columns) 30 | &.is-tablet-{$n} 31 | min-width: round($n / $columns * 100%, $round-digits) 32 | width: round($n / $columns * 100%, $round-digits) 33 | 34 | &.is-offset-tablet-{$n} 35 | margin-{$dir-start}: round($n / $columns * 100%, $round-digits) 36 | 37 | +desktop() 38 | for $n in (0 .. $columns) 39 | &.is-desktop-{$n} 40 | min-width: round($n / $columns * 100%, $round-digits) 41 | width: round($n / $columns * 100%, $round-digits) 42 | 43 | &.is-offset-desktop-{$n} 44 | margin-{$dir-start}: round($n / $columns * 100%, $round-digits) 45 | 46 | +widescreen() 47 | for $n in (0 .. $columns) 48 | &.is-widescreen-{$n} 49 | min-width: round($n / $columns * 100%, $round-digits) 50 | width: round($n / $columns * 100%, $round-digits) 51 | 52 | &.is-offset-widescreen-{$n} 53 | margin-{$dir-start}: round($n / $columns * 100%, $round-digits) 54 | 55 | +ultrawide() 56 | for $n in (0 .. $columns) 57 | &.is-ultrawide-{$n} 58 | min-width: round($n / $columns * 100%, $round-digits) 59 | width: round($n / $columns * 100%, $round-digits) 60 | 61 | &.is-offset-ultrawide-{$n} 62 | margin-{$dir-start}: round($n / $columns * 100%, $round-digits) 63 | 64 | &.is-middle 65 | align-self: center 66 | 67 | &.is-top 68 | align-self: flex-start 69 | 70 | &.is-bottom 71 | align-self: flex-end 72 | 73 | >.row 74 | margin: 0 ($gutter * -1) 75 | min-width: 'calc(100% + %s)' % ($gutter * 2) 76 | -------------------------------------------------------------------------------- /src/components/tooltip.styl: -------------------------------------------------------------------------------- 1 | [tooltip] 2 | position: relative 3 | 4 | &:focus 5 | outline: none 6 | 7 | &:hover 8 | &:before, &:after 9 | visibility: visible 10 | opacity: 1 11 | 12 | &:before 13 | position: absolute 14 | top: 0 15 | left: 50% 16 | z-index: 99999 17 | display: block 18 | visibility: hidden 19 | width: 0 20 | height: 0 21 | border-width: 7px 7px 0 7px 22 | border-style: solid 23 | border-color: $black transparent transparent transparent 24 | content: '' 25 | opacity: 0 26 | transition: 0.4s 27 | transform: translateX(-50%) translateY(-100%) 28 | user-select: none 29 | 30 | &:after 31 | position: absolute 32 | top: 0 33 | left: 50% 34 | z-index: 99999 35 | display: block 36 | visibility: hidden 37 | padding: $padding 38 | border-radius: $border-radius 39 | background-color: $black 40 | color: $white 41 | content: attr(tooltip) 42 | white-space: nowrap 43 | opacity: 0 44 | transition: 0.4s 45 | transform: translateX(-50%) translateY(-100%) translateY(-6px) 46 | user-select: none 47 | @extends $small 48 | 49 | [tooltip-position='bottom'] 50 | &:before 51 | top: auto 52 | top: initial 53 | bottom: 0 54 | border-width: 0 7px 7px 7px 55 | border-color: transparent transparent $black transparent 56 | transform: translateX(-50%) translateY(100%) 57 | 58 | &:after 59 | top: auto 60 | top: initial 61 | bottom: 0 62 | transform: translateX(-50%) translateY(100%) translateY(6px) 63 | 64 | 65 | [tooltip-position='left'] 66 | &:before 67 | top: 50% 68 | left: 0 69 | border-width: 7px 0 7px 7px 70 | border-color: transparent transparent transparent $black 71 | transform: translateX(-100%) translateY(-50%) 72 | 73 | &:after 74 | top: 50% 75 | left: 0 76 | transform: translateX(-100%) translateX(-6px) translateY(-50%) 77 | 78 | [tooltip-position='right'] 79 | &:before 80 | top: 50% 81 | right: 0 82 | left: auto 83 | left: initial 84 | border-width: 7px 7px 7px 0 85 | border-color: transparent $black transparent transparent 86 | transform: translateX(100%) translateY(-50%) 87 | 88 | &:after 89 | top: 50% 90 | right: 0 91 | left: auto 92 | left: initial 93 | transform: translateX(100%) translateX(6px) translateY(-50%) 94 | 95 | [tooltip-rounded] 96 | &:after 97 | border-radius: 10em -------------------------------------------------------------------------------- /src/components/nav.styl: -------------------------------------------------------------------------------- 1 | .nav 2 | padding: $padding 3 | background-color: $white 4 | scroll-behavior: smooth 5 | 6 | &.has-icons .nav-submenu 7 | padding: 0.75em 0.75em 0.75em 2.2em 8 | 9 | .nav-label 10 | font-weight: $font-weight-bold 11 | padding: 0.75em 1em 12 | color: $black 13 | font-size: $font-size[2] 14 | margin: 1em 0 15 | 16 | .nav-menu, .nav-submenu 17 | margin: $margin 0 18 | list-style: none 19 | padding-{$dir-start}: 0 20 | 21 | .nav-submenu 22 | display: none 23 | padding: 0.75em 24 | 25 | .nav-link 26 | border-radius: 0 27 | padding: 0.5em 0.75em 28 | 29 | &.is-active 30 | color: $primary 31 | border-{$dir-start}-width: 2px 32 | border-style: solid 33 | border-color: $primary 34 | 35 | .nav-wrapper 36 | overflow: hidden 37 | 38 | .nav-link, .nav-toggle 39 | display: flex 40 | align-items: center 41 | position: relative 42 | display: block 43 | border-radius: $border-radius 44 | padding: 0.75em 1em 45 | color: $black 46 | background: transparent 47 | border: 0 48 | width: 100% 49 | text-align: $dir-start 50 | cursor: pointer 51 | @extend $normal 52 | 53 | &:focus, .is-active 54 | outline: none 55 | color: $primary 56 | 57 | &:hover 58 | color: $primary 59 | 60 | .icon 61 | margin-{$dir-end}: $margin 62 | 63 | .nav-icon 64 | width: 15px 65 | height: 15px 66 | position: absolute 67 | {$dir-end}: 10px 68 | top: 50% 69 | transform: translateY(-50%) 70 | display: flex 71 | align-items: center 72 | pointer-events: none 73 | 74 | &:after, &:before 75 | width: 7.5px 76 | height: 2px 77 | content: '' 78 | display: block 79 | background: $gray 80 | transition: transform 0.2s ease-in-out 81 | 82 | &:after 83 | transform: rotate(-45deg) 84 | margin-{$dir-start}: -1.75px 85 | 86 | &:before 87 | transform: rotate(45deg) 88 | margin-{$dir-end}: -1.75px 89 | 90 | .nav-item.is-active & 91 | &:after 92 | transform: rotate(45deg) 93 | background: $primary 94 | 95 | &:before 96 | transform: rotate(-45deg) 97 | background: $primary 98 | 99 | .nav-item 100 | margin-top: 0 101 | list-style: none 102 | 103 | &.is-active 104 | .nav-submenu 105 | display: block 106 | 107 | .nav-toggle 108 | color: $primary 109 | font-weight: $font-weight-medium 110 | box-shadow: boxShadow(small) 111 | -------------------------------------------------------------------------------- /src/components/table.styl: -------------------------------------------------------------------------------- 1 | .table 2 | overflow: hidden 3 | width: 100% 4 | border-spacing: 0 5 | border-collapse: separate 6 | border-radius: $border-radius-large 7 | overflow: hidden 8 | color: $black 9 | text-align: $dir-start 10 | 11 | &:not(:last-child) 12 | margin-bottom: $margin 13 | 14 | 15 | thead 16 | font-weight: $font-weight-bold 17 | th 18 | border-top: 0 19 | border-bottom: $border solid $gray 20 | tfoot 21 | th 22 | border-top: $border solid $gray 23 | padding: ($padding * 2) $padding 24 | 25 | td, 26 | th 27 | padding: ($padding * 2) $padding 28 | border-top: $border solid $gray 29 | 30 | // generate size modifiers 31 | generateSizes() 32 | 33 | &.is-striped 34 | tbody tr:nth-of-type(odd) 35 | background-color: $light 36 | 37 | &.is-bordered 38 | border: $border solid $gray 39 | th, 40 | td 41 | &:not(:last-child) 42 | border-{$dir-end}: $border solid $gray 43 | 44 | &.is-clean 45 | td 46 | border-top: 0 47 | &.is-hoverable 48 | tr:hover 49 | background-color: $light 50 | 51 | &.is-center 52 | text-align: center 53 | 54 | &.is-top tbody 55 | vertical-align: top 56 | 57 | &.is-bottom tbody 58 | vertical-align: bottom 59 | 60 | &.is-middle tbody 61 | vertical-align: middle 62 | 63 | &.is-header-centerd 64 | th 65 | text-align: center 66 | &.is-header-highlighted 67 | th 68 | background-color: $light 69 | 70 | &.is-mobile-colapsed 71 | th, td 72 | &:not(:last-child) 73 | +mobile() 74 | border-right: 0 75 | +mobile() 76 | display: block 77 | width: 100% 78 | thead 79 | th 80 | +mobile() 81 | border-bottom: 0 82 | tr 83 | +mobile() 84 | display: block 85 | border-top: $border solid $gray 86 | 87 | td 88 | +mobile() 89 | border: 0 90 | 91 | tr 92 | for color in $modifiers-color 93 | $accent = lookup('$' + color) 94 | $text = isLight(color) ? $black : $white 95 | &.is-{color} 96 | &.is-{color}:hover 97 | background-color: $accent 98 | color: $text 99 | .table-responsive 100 | display: block; 101 | width: 100%; 102 | overflow-x: auto; 103 | 104 | .table-sort 105 | float: right 106 | padding: 0 107 | outline: 0 108 | background: none 109 | border: none 110 | 111 | &.is-active 112 | fill: $primary 113 | stroke: $primary 114 | 115 | &.is-desc 116 | transform: scaleY(-1) -------------------------------------------------------------------------------- /extensions/navbar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

Blexar Navbar

15 |

A navabar is the main element to navigate across the website

16 |
17 | 18 |
19 | 56 |
57 |
58 | 59 | 60 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /extensions/dropdown/README.md: -------------------------------------------------------------------------------- 1 | # Dropdown 2 | 3 | Extension for Blexar framework to handle dropdowns with accessibility (a11y) in mind. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | You can install dropdown as part of all blexar's extensions. 10 | 11 | ```bash 12 | npm install @blexar/extensions 13 | 14 | # or using yarn 15 | yarn add @blexar/extensions 16 | ``` 17 | 18 | If you want the standalone version. 19 | 20 | ```bash 21 | npm install @blexar/dropdown 22 | 23 | yarn add @blexar/dropdown 24 | ``` 25 | 26 | ### Include necessary files 27 | 28 | ``` html 29 | 30 | 31 | 32 | 33 | 34 | ... 35 | 36 | 37 | ``` 38 | 39 | ### HTML Layout 40 | 41 | * `.dropdown` 42 | * `[data-base-dropdown]` 43 | * `.dropdown-menu` 44 | 45 | ``` html 46 | 47 | 48 | 61 | ``` 62 | 63 | Once you include the script file, it will search for an element with `[data-base-dropdown]` attribute and initialize new `Dropdown` instance. 64 | Note: you add `[data-base-dropdown]` attribute to the button element and its value will serve as a CSS selector for the `.dropdown-menu` 65 | 66 | ### Initialize with JavaScript 67 | 68 | If there's no element with `[data-base-dropdown]` attribute, you have to create a new `Dropdown` instance manually. 69 | 70 | ```js 71 | const newDropdown = new Dropdown('#buttonSelector', '#menuSelector'[, settings]); 72 | ``` 73 | 74 | | OPTION | DEFAULT | DESCRIPTION | 75 | | ------ | ------- | ----------- | 76 | | menuVisible | 'is-visible' | class name for when the menu is visible | 77 | | menuHidden | 'is-hidden' | class name for when the menu is hidden | 78 | | elementActive | 'is-active' | class name for when the button is active | 79 | | hideWhenClickOut | false | set `true` to close the menu when clicking outside of it | 80 | 81 | ## License 82 | 83 | [MIT](http://opensource.org/licenses/MIT) 84 | 85 | Copyright (c) 2017 [Baianat](http://baianat.com) 86 | -------------------------------------------------------------------------------- /extensions/slider/README.md: -------------------------------------------------------------------------------- 1 | # Range slider 2 | 3 | Range slider extension with gradient color range for Blexar framework. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | You can install slider as part of all blexar's extensions. 10 | 11 | ```bash 12 | npm install @blexar/extensions 13 | 14 | # or using yarn 15 | yarn add @blexar/extensions 16 | ``` 17 | 18 | If you want the standalone version. 19 | 20 | ```bash 21 | npm install @blexar/slider 22 | 23 | yarn add @blexar/slider 24 | ``` 25 | 26 | ### Include necessary files 27 | 28 | ``` html 29 | 30 | 31 | 32 | 33 | 34 | ... 35 | 36 | 37 | ``` 38 | 39 | ### HTML Layout 40 | 41 | You need an input element to print the output value in it. 42 | 43 | ``` html 44 | 45 | 46 | 55 | ``` 56 | 57 | You can also add value, min, max and step values using input attributes. 58 | 59 | ``` html 60 | 61 | 62 | 65 | ``` 66 | 67 | ### Settings 68 | 69 | | PROPERTIES | DEFAULT | DESCRIPTION | 70 | | ---------- | ------- | ----------------------------------- | 71 | | gradient | null | slider gradient colors array | 72 | | classes | null | classes to add to range slider | 73 | | colorCode | false | show color code instead of value | 74 | | editable | false | can input the slider value directly | 75 | | label | true | show/hide value label | 76 | | min | 0 | minimum slider value | 77 | | max | 10 | maximum slider value | 78 | | step | 1 | limit the increments value | 79 | | value | 0 | start value | 80 | 81 | ### Methods 82 | 83 | You can call method on `Slider` instance. 84 | 85 | ```js 86 | const mySlider = new Slider('#slider'); 87 | mySlider.selectColor('#ff00ff'); 88 | ``` 89 | 90 | | METHOD | ARGUMENT | DESCRIPTION | 91 | | ------ | -------- | ----------- | 92 | | `update` | [Number] value, [Bool] mute | change the slider current value | 93 | | `newGradient` | [Array] newGradient | change the current slider gradient| 94 | 95 | ## License 96 | 97 | [MIT](http://opensource.org/licenses/MIT) 98 | 99 | Copyright (c) 2017 [Baianat](http://baianat.com) 100 | -------------------------------------------------------------------------------- /extensions/switcher/src/switcher.js: -------------------------------------------------------------------------------- 1 | import select from '../../_utils/select'; 2 | 3 | class Switcher { 4 | constructor (el) { 5 | this.el = select(el); 6 | this._init(); 7 | } 8 | 9 | _init() { 10 | this.body = this.el.querySelector('.switcher-body'); 11 | this.handle = this.el.querySelector('.switcher-handle'); 12 | this.input = this.el.querySelector('.switcher-input'); 13 | this.status = this.input.checked; 14 | this.currentX = 0; 15 | this.tempDrag = ''; 16 | this.tempRelease = ''; 17 | this.dragValue = 0; 18 | this._initEvents(); 19 | } 20 | 21 | _initEvents () { 22 | this.body.addEventListener('touchstart', (event) => { 23 | this.currentX = event.touches[0].clientX; 24 | this.moved = 0; 25 | document.addEventListener('touchmove', this.tempDrag = (evnt) => this.drag(evnt), false); 26 | document.addEventListener('touchend', this.tempRelease = (evnt) => this.release(evnt), false); 27 | }, false); 28 | 29 | this.body.addEventListener('mousedown', (event) => { 30 | if (event.buttons !== 1) return; 31 | this.currentX = event.clientX; 32 | this.moved = 0; 33 | document.addEventListener('mousemove', this.tempDrag = (evnt) => this.drag(evnt), false); 34 | document.addEventListener('mouseup', this.tempRelease = (evnt) => this.release(evnt), false); 35 | }, false); 36 | 37 | this.body.addEventListener('click', (event) => event.preventDefault()); 38 | } 39 | 40 | drag (event) { 41 | if (event.type === 'mousemove') { 42 | this.dragValue = (event.clientX - this.currentX); 43 | } 44 | if (event.type === 'touchmove') { 45 | this.dragValue = (event.touches[0].clientX - this.currentX); 46 | } 47 | this.handle.classList.add('is-dragging'); 48 | const switcherWidth = this.body.clientWidth; 49 | const handleWidth = this.handle.clientWidth; 50 | this.movingRange = switcherWidth - handleWidth - (0.625 * handleWidth); 51 | 52 | this.moved = (this.status ? -1 : 1) * this.dragValue; 53 | this.dragValue = this.status 54 | ? Math.max(Math.min(this.dragValue, 0), -this.movingRange) 55 | : Math.min(Math.max(this.dragValue, 0), this.movingRange) 56 | this.handle.style.transition = '0s'; 57 | this.handle.style.transform = `translate3d(${this.dragValue}px, 0, 0)`; 58 | } 59 | 60 | release (event) { 61 | if (this.moved >= (this.movingRange / 4) || this.moved === 0) { 62 | this.input.checked = !this.input.checked; 63 | } 64 | 65 | this.status = this.input.checked; 66 | this.handle.style.transform = ''; 67 | this.handle.style.transition = ''; 68 | this.handle.classList.remove('is-dragging'); 69 | 70 | document.removeEventListener('mousemove', this.tempDrag); 71 | document.removeEventListener('mouseup', this.tempRelease); 72 | document.removeEventListener('touchmove', this.tempDrag); 73 | document.removeEventListener('touchend', this.tempRelease); 74 | } 75 | } 76 | 77 | export default Switcher; 78 | -------------------------------------------------------------------------------- /src/util/elements-mixins.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * styling mixins 3 | */ 4 | 5 | _icon-color(color) 6 | fill: color 7 | 8 | _button-color(accent, text) 9 | &.is-outlined 10 | &.is-bright 11 | &.is-clean:hover 12 | &.is-clean:active 13 | &.is-clean.is-active 14 | color: accent 15 | _icon-color: accent 16 | &.is-outlined 17 | border-color: accent 18 | &.is-bright 19 | background-color: lighten(accent, 85%) 20 | &:hover 21 | &:active 22 | &.is-active 23 | background-color: darken(accent, 15%) 24 | color: text 25 | _icon-color: text 26 | &:focus:not(:active) 27 | box-shadow: 0 0 0 $outline alpha(accent, $outline-opacity) 28 | & 29 | &.is-disabled 30 | &[disabled] 31 | background-color: accent 32 | color: text 33 | _icon-color: text 34 | 35 | _file-color(accent, text) 36 | & 37 | background-color: accent 38 | color: text 39 | _icon-color: text 40 | 41 | _alert-color(accent, text) 42 | &.is-outlined 43 | &.is-bright 44 | color: accent 45 | _icon-color: accent 46 | &.is-outlined 47 | border-color: accent 48 | &.is-bright 49 | background-color: lighten(accent, 85%) 50 | & 51 | background-color: accent 52 | color: text 53 | _icon-color: text 54 | 55 | _button-grad(grad, text) 56 | background-image: linear-gradient($grad-direction, grad[0], grad[1]) 57 | color: text 58 | _icon-color: text 59 | 60 | 61 | _textarea-color(primary, secondary = primary) 62 | border-color: primary 63 | &:focus 64 | border-color: darken(secondary, 15%) 65 | box-shadow: 0 0 0 $outline alpha(secondary, $outline-opacity) 66 | 67 | _input-color(primary, secondary = primary) 68 | border-color: primary 69 | &:focus 70 | border-color: darken(secondary, 15%) 71 | box-shadow: 0 0 0 $outline alpha(secondary, $outline-opacity) 72 | 73 | _select-color(primary, secondary) 74 | border-color: primary 75 | color: secondary 76 | .select-label, 77 | .select-item.is-selected, 78 | .select-childItem.is-selected 79 | background-color: secondary 80 | color: $white 81 | .select-item:not(.is-group):hover, 82 | .select-childItem:hover 83 | background-color: darken(secondary, 15%) 84 | color: $white 85 | &:focus 86 | border-color: darken(primary, 15%) 87 | box-shadow: 0 0 0 $outline alpha(primary, $outline-opacity) 88 | 89 | 90 | _modal-color(accent, textColor) 91 | background-color: lighten(accent, 85%) 92 | color: textColor 93 | _icon-color: textColor 94 | &.is-outline 95 | border-color: accent 96 | color: accent 97 | _icon-color: accent 98 | &:focus 99 | border-color: accent 100 | box-shadow: 0 0 0 $outline alpha(accent, $outline-opacity) 101 | 102 | _label-color(accent, textColor) 103 | background-color: accent 104 | color: textColor 105 | _icon-color: textColor -------------------------------------------------------------------------------- /extensions/table/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

Blexar Table

15 |

A table used to organize data

16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
NameInfoPriceAction
Total
37 |
38 | 39 | 40 | 74 | 75 | 76 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /extensions/table/README.md: -------------------------------------------------------------------------------- 1 | # Table 2 | 3 | Advanced data table extension for Blexar framework. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | You can install table as part of all blexar's extensions. 10 | 11 | ```bash 12 | npm install @blexar/extensions 13 | 14 | # or using yarn 15 | yarn add @blexar/extensions 16 | ``` 17 | 18 | If you want the standalone version. 19 | 20 | ```bash 21 | npm install @blexar/table 22 | 23 | yarn add @blexar/table 24 | ``` 25 | 26 | ### Include necessary files 27 | 28 | ``` html 29 | 30 | 31 | 32 | 33 | 34 | ... 35 | 36 | 37 | ``` 38 | 39 | ### HTML markup 40 | 41 | Here's an ordinary table markup with the class `.table` 42 | 43 | ``` html 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ... 56 | 57 | 58 | 59 | ... 60 | 61 |
NameInfoPriceAction
62 | ``` 63 | 64 | ### Create a new table instance 65 | 66 | using default settings 67 | 68 | ``` javascript 69 | new Table('.table'); 70 | ``` 71 | 72 | using custom settings 73 | 74 | ``` javascript 75 | new Table('.table', { 76 | fixedHeader: true, 77 | pagination: true, 78 | sortable: true, 79 | editable: true, 80 | density: false, 81 | perPage: 10 82 | }); 83 | ``` 84 | 85 | ### Settings 86 | 87 | | PROPERTIES | DEFAULT | DESCRIPTION | 88 | | ------------ | -------- | ------------------------------------------------------------ | 89 | | fixedHeader | false | indicates whether the table header is fixed during scrolling | 90 | | pagination | true | enables pages pagination | 91 | | sortable | true | enables the ability to sort columns | 92 | | editable | false | enables the user to edit table cells | 93 | | density | false | shows rows density control buttons | 94 | | perPage | 10 | how many rows is shown per page | 95 | 96 | ### Working with custom events 97 | 98 | You can listen to events to notify you when data changes 99 | 100 | ``` javascript 101 | const table = document.querySelector('.table'); 102 | 103 | table.addEventListener('beforeEdit', (e) => { 104 | console.log(e.detail) 105 | }); 106 | 107 | table.addEventListener('afterEdit', (e) => { 108 | console.log(e.detail) 109 | }); 110 | ``` 111 | 112 | ### Events 113 | 114 | | DEFAULT | DESCRIPTION | 115 | | ---------- | --------------------------------------------- | 116 | | beforeEdit | fires when clicking on an input and starts to edit it | 117 | | afterEdit | fires after blurring out of the input | 118 | 119 | ## License 120 | 121 | [MIT](http://opensource.org/licenses/MIT) 122 | 123 | Copyright (c) 2017 [Baianat](http://baianat.com) 124 | -------------------------------------------------------------------------------- /src/components/button.styl: -------------------------------------------------------------------------------- 1 | .button 2 | position: relative 3 | display: inline-flex 4 | align-items: center 5 | justify-content: center 6 | margin-bottom: $margin 7 | padding: $padding ($padding * 1.5) 8 | outline: none 9 | border-style: solid 10 | border-radius: $border-radius 11 | border-color: transparent 12 | border-width: $border 13 | background-clip: border-box 14 | vertical-align: middle 15 | text-align: center 16 | text-decoration: none 17 | user-select: none 18 | cursor: pointer 19 | line-height: $element-lineheight 20 | _button-color: $gray $dark 21 | 22 | &:not(:last-child) 23 | margin-{$dir-end}: $margin 24 | 25 | // generate size modifiers 26 | generateSizes() 27 | 28 | // generate color modifiers 29 | for color in $modifiers-color 30 | $accent = lookup('$' + color) 31 | $text = isLight(color) ? $black : $white 32 | 33 | &.is-{color} 34 | _button-color: $accent $text 35 | 36 | // generate gradient modifiers 37 | for color in $modifiers-color-grad 38 | $grad = lookup('$grad-' + color) 39 | 40 | &.is-{color}.is-gradient 41 | _button-grad: $grad $white 42 | 43 | &.is-gradient 44 | background-color: transparent 45 | background-position: -1px -1px 46 | background-size: calc(100% + 4px) calc(100% + 4px) 47 | 48 | &:focus:not(:active) 49 | box-shadow: 0 0 0 $outline alpha($primary, $outline-opacity) 50 | 51 | &:hover, &:active, &.is-active 52 | opacity: 0.8 53 | 54 | .is-disabled, &[disabled] 55 | border-color: $primary 56 | background-color: $primary 57 | 58 | .icon 59 | &:first-child:not(:last-child) 60 | margin-{$dir-end}: ($padding * 0.5) 61 | 62 | &:last-child:not(:first-child) 63 | margin-{$dir-start}: ($padding * 0.5) 64 | 65 | &:only-child 66 | margin: 0 ($padding * -0.5) 67 | 68 | .label 69 | margin: ($padding * -1) 0 70 | 71 | &.is-block 72 | width: 100% 73 | 74 | &.is-rounded 75 | border-radius: 10em 76 | 77 | &.is-outlined 78 | background-color: transparent 79 | border-style: solid 80 | border-width: $border 81 | 82 | &.is-clean 83 | padding: $padding 84 | color: $dark 85 | _icon-color: $dark 86 | 87 | &, &:hover, &:active, &:focus, &.is-active 88 | background-color: transparent 89 | 90 | &.is-link 91 | padding-top: 0.3em 92 | padding-bottom: 0.3em 93 | padding-{$dir-start}: 0 94 | padding-{$dir-end}: 0.7em 95 | border: 0 96 | background-color: transparent 97 | color: $link 98 | _icon-color: $link 99 | 100 | &:after 101 | position: absolute 102 | display: block 103 | content: '' 104 | width: 100% 105 | height: 0.15em 106 | background-color: $link 107 | bottom: 0 108 | left: 0 109 | right: 0 110 | 111 | &:hover, &:active, &.is-active 112 | color: $link-hover 113 | 114 | &:after 115 | background-color: $link-hover 116 | height: 0.25em 117 | 118 | &:hover 119 | text-decoration: none 120 | 121 | &.is-disabled, &[disabled] 122 | opacity: 0.8 123 | cursor: not-allowed 124 | 125 | @keyframes spinner-rotation 126 | to 127 | transform: rotate(360deg) -------------------------------------------------------------------------------- /extensions/navbar/README.md: -------------------------------------------------------------------------------- 1 | # Navbar 2 | 3 | An adaptive navbar extension for Blexar framework, that moves navbar elements to a dropdown menu based on pre-set priorities. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | You can install navbar as part of all blexar's extensions. 10 | 11 | ```bash 12 | npm install @blexar/extensions 13 | 14 | # or using yarn 15 | yarn add @blexar/base.extensions 16 | ``` 17 | 18 | If you want the standalone version. 19 | 20 | ```bash 21 | npm install @blexar/navbar 22 | 23 | yarn add @blexar/navbar 24 | ``` 25 | 26 | ### Include necessary files 27 | 28 | ``` html 29 | 30 | 31 | 32 | 33 | 34 | ... 35 | 36 | 37 | ``` 38 | 39 | ### HTML Layout 40 | 41 | * `.navbar` 42 | * `.dropdown[data-nav-dropdown]` 43 | * `.navbar-item[data-nav-button]` 44 | * `.dropdown-menu[data-nav-menu]` 45 | * `[data-nav-items]` 46 | * `.navbar-item[data-nav-priority]` 47 | * `.navbar-item[data-nav-priority]` 48 | * ... 49 | 50 | ```html 51 | 82 | ``` 83 | 84 | create a new `Navbar` instance using JavaScript 85 | 86 | ```javascript 87 | new Navbar('#main-navbar'); 88 | ``` 89 | 90 | ### customization 91 | 92 | There are three levels of priorities, based on which, the items are moved from the navbar to the dropdown menu. Low priority items are moved first outside the navbar. 93 | 94 | You can define the priorities using the `data-nav-priority` attribute 95 | 96 | ```HTML 97 | 111 | ``` 112 | 113 | > Note that if you didn't define a priority for an item, it will be set as low priority 114 | -------------------------------------------------------------------------------- /extensions/select/README.md: -------------------------------------------------------------------------------- 1 | # Select 2 | 3 | Select extension for Blexar framework 4 | 5 | [example](https://baianat.github.io/select/) 6 | 7 | ## How to use 8 | 9 | ### Install 10 | 11 | You can install navbar as part of all blexar's extensions. 12 | 13 | ```bash 14 | npm install @blexar/extensions 15 | 16 | # or using yarn 17 | yarn add @blexar/base.extensions 18 | ``` 19 | 20 | If you want the standalone version. 21 | 22 | ```bash 23 | npm install @blexar/select 24 | 25 | yarn add @blexar/select 26 | ``` 27 | 28 | ### Include necessary files 29 | 30 | ``` html 31 | 32 | 33 | 34 | 35 | 36 | ... 37 | 38 | 39 | 40 | ``` 41 | 42 | ### Create select element 43 | 44 | There are two ways to get your `Select` data source, from HTML select markup or pass them as an array of values to data object. 45 | 46 | #### From HTML select markup 47 | 48 | ```html 49 | 62 | 63 | 66 | ``` 67 | 68 | #### Passing values to data object 69 | 70 | ```html 71 | 96 | ``` 97 | 98 | or set multiple to `true` 99 | 100 | ```javaScript 101 | const newSelect = new Select('#select', { 102 | multiple: true 103 | }); 104 | ``` 105 | 106 | ### Settings 107 | 108 | | Properties | Default | Description | 109 | | :--------: | :-----: | :------------------------------: | 110 | | data | null | generate the options values | 111 | | multiple | false | enable/disable multiple mode | 112 | 113 | ### Methods 114 | 115 | You can call method on `Select` instance. 116 | 117 | ```javascript 118 | const newSelect = new Select('#select'); 119 | 120 | newSelect.showMenu(); 121 | ``` 122 | 123 | | Method | Argument | Description | 124 | | :------------: | :-------------: | :---------: | 125 | | `menuShow` | | show select options menu | 126 | | `menuHide` | | hide select options menu | 127 | | `menuToggle` | | toggle options menu visibility | 128 | | `selectOption` | [Object] option | select option | 129 | | `updateLabels` | | (in multiple mode only) update the labels | 130 | 131 | ## License 132 | 133 | [MIT](http://opensource.org/licenses/MIT) 134 | 135 | Copyright (c) 2017 [Baianat](http://baianat.com) 136 | -------------------------------------------------------------------------------- /src/components/select.styl: -------------------------------------------------------------------------------- 1 | .select 2 | position: relative 3 | margin-bottom: $margin 4 | padding: $padding ($padding * 1.5) 5 | max-width: 100% 6 | width: 100% 7 | outline: none 8 | border-width: $border 9 | border-style: solid 10 | border-radius: $border-radius 11 | background-color: $white 12 | background-position: right 0.75em center 13 | background-size: 0.5em 14 | background-repeat: no-repeat 15 | text-align: left 16 | -webkit-appearance: none 17 | -moz-appearance: none 18 | _select-color: $gray $primary 19 | 20 | &:not([multiple]) 21 | background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#D4D2E5' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") 22 | 23 | /* 24 | * select elments 25 | */ 26 | &-input 27 | display: flex 28 | padding: 0 29 | border: 0 30 | outline: none 31 | background-color: transparent 32 | color: inherit 33 | text-align: left 34 | font-size: inherit 35 | -webkit-appearance: textfield 36 | -moz-appearance: none 37 | 38 | select 39 | display: none 40 | 41 | &-labels 42 | position: absolute 43 | top: 0 44 | {$dir-start}: 0 45 | display: inline-flex 46 | flex-wrap: wrap 47 | margin-{$dir-end}: 2em 48 | padding: 0 49 | 50 | &-label 51 | display: inline-flex 52 | justify-content: center 53 | align-items: center 54 | overflow: hidden 55 | margin: 0.2em 56 | padding: 0.4em 57 | border-radius: $border-radius 58 | background-color: $black 59 | color: $white 60 | font-size: 1em 61 | line-height: 1 62 | _icon-color: currentColor 63 | 64 | &-labelDismiss 65 | width: 1em 66 | height: 1em 67 | color: currentColor 68 | 69 | &:hover 70 | fill: $gray 71 | 72 | &-menu 73 | position: absolute 74 | top: 100% 75 | right: 0 76 | left: 0 77 | z-index: 999 78 | margin: 0 (- $border) 79 | border-width: 0 $border $border $border 80 | border-style: solid 81 | border-color: inherit 82 | border-radius: 0 0 $border-radius $border-radius 83 | background: $white 84 | font-size: inherit 85 | 86 | &-list 87 | overflow: auto 88 | margin: 0 89 | padding: 0 90 | max-height: 40vh 91 | list-style: none 92 | 93 | &-item 94 | padding: 0 95 | width: 100% 96 | 97 | &:not(.is-group) 98 | padding: $padding 99 | cursor: pointer 100 | 101 | &-childMenu 102 | margin: 0 103 | padding: 0 104 | list-style: none 105 | 106 | &-childTitle 107 | display: block 108 | padding: $padding 109 | color: $gray 110 | 111 | &-childItem 112 | padding: $padding $padding $padding ($padding * 2) 113 | cursor: pointer 114 | 115 | // generate size modifiers 116 | generateSizes() 117 | 118 | // generate color modifiers 119 | for color in $modifiers-color 120 | $color = lookup('$' + color) 121 | $text = isLight(color) ? $black : $color 122 | 123 | &.is-{color} 124 | _select-color: $color $text 125 | 126 | .is-visible 127 | display: block 128 | 129 | .is-hidden 130 | display: none 131 | 132 | &.is-rounded 133 | border-radius: 10em 134 | 135 | &:disabled, &.is-disabled 136 | opacity: 0.7 137 | cursor: not-allowed 138 | 139 | &.is-active 140 | border-bottom-left-radius: 0 141 | border-bottom-right-radius: 0 142 | 143 | &.is-disabled 144 | opacity: 0.7 145 | pointer-events: none -------------------------------------------------------------------------------- /extensions/dropdown/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Blexar Dropdown 8 | 9 | 10 | 11 |
12 |
13 |

Blexar Dropdown

14 |

A dropdown component groups multiple elements in a menu, that can be toggle visible or not

15 |
16 |
17 |
18 |

Right

19 |
20 |
21 | 31 |
32 |
33 |

Center

34 |
35 |
36 | 46 |
47 |
48 |

Left

49 |
50 |
51 | 61 |
62 | 63 |
64 |

Hide when click out

65 |
66 |
67 | 77 |
78 |
79 |
80 | 81 | 82 | 92 | 93 | -------------------------------------------------------------------------------- /extensions/slider/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Rangeslider 9 | 10 | 11 |
12 |
13 |

Blexar Slider

14 |

A slider allows a user to select a value from a range

15 |
16 |
17 |
18 |

Default

19 |
20 |
21 | 22 |
23 | 24 |
25 |

Gradient with opacity

26 |
27 |
28 | 29 |
30 | 31 |
32 |

Gradient

33 |
34 |
35 | 36 |
37 | 38 |
39 |

Editable

40 |
41 |
42 | 43 |
44 | 45 |
46 |

Hue colors

47 |
48 |
49 | 50 |
51 |
52 |

Multiple handles

53 |
54 |
55 |
56 |
57 |
58 |
59 | 60 | 61 | 62 | 136 | 137 | -------------------------------------------------------------------------------- /extensions/switcher/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | base 8 | 9 | 10 | 11 |
12 |
13 |

Blexar Slider

14 |

A switcher allows a user to select a value from yes or no

15 |
16 |
17 |
18 |

Default

19 |
20 |
21 | 27 |
28 | 29 |
30 |

With caption

31 |
32 |
33 | 41 |
42 | 43 |
44 |

Tiny

45 |
46 |
47 | 53 |
54 | 55 |
56 |

Small

57 |
58 |
59 | 65 |
66 | 67 |
68 |

Normal

69 |
70 |
71 | 77 |
78 | 79 |
80 |

Large

81 |
82 |
83 | 89 |
90 | 91 |
92 |

Massive

93 |
94 |
95 | 101 |
102 | 103 |
104 |

Radio buttons

105 |
106 |
107 | 113 | 119 | 125 |
126 | 127 |
128 |
129 | 130 | 131 | 134 | 135 | -------------------------------------------------------------------------------- /extensions/select/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Document 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Blexar Navbar

17 |

A navabar is the main element to navigate across the website

18 |
19 |
20 |
21 |

Multiple with groups

22 |
23 |
24 | 34 |
35 | 36 |
37 |

Multiple without groups

38 |
39 | 40 |
41 | 58 |
59 | 60 |
61 |

Multiple from data

62 |
63 |
64 | 65 |
66 | 67 |
68 |

Single

69 |
70 |
71 | 77 |
78 | 79 |
80 |

Single with groups

81 |
82 |
83 | 93 |
94 | 95 |
96 |

Single from data

97 |
98 |
99 | 100 |
101 |
102 | 103 | 104 | 105 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /extensions/table/src/paginator.js: -------------------------------------------------------------------------------- 1 | import select from '../../_utils/select'; 2 | import toArray from '../../_utils/toArray'; 3 | 4 | export default class Paginator { 5 | constructor(el, settings = {}) { 6 | this.el = select(el); 7 | this.settings = settings; 8 | this.init(); 9 | } 10 | 11 | /** 12 | * init paginator 13 | */ 14 | init() { 15 | this.currentPage = 1; 16 | this.items = this._normalizeTableData();; 17 | this.allItems = []; 18 | this._chunk(this.settings.perPage); 19 | } 20 | 21 | /** 22 | * return number of pages in table 23 | */ 24 | get totalPageCount() { 25 | return this.allItems.length; 26 | } 27 | 28 | /** 29 | * Renders the in-memory changes done to a table. 30 | */ 31 | render() { 32 | const fragment = document.createDocumentFragment(); 33 | this.items.forEach((item) => { 34 | const row = document.createElement('tr'); 35 | this.columns.forEach((key) => { 36 | const cell = document.createElement('td'); 37 | cell.innerText = item[key]; 38 | row.appendChild(cell); 39 | if (this.settings.editable) { 40 | cell.addEventListener('click', () => this.edit(item.id, key)); 41 | } 42 | }); 43 | row.addEventListener('getId', () => { 44 | return item; 45 | }, false); 46 | fragment.appendChild(row); 47 | }); 48 | 49 | this.el.tBodies[0].innerHTML = ''; 50 | this.el.tBodies[0].appendChild(fragment); 51 | } 52 | 53 | /** 54 | * update table with next items 55 | */ 56 | nextPage() { 57 | this.paginateTo(this.currentPage + 1); 58 | this.render(); 59 | } 60 | 61 | /** 62 | * update table with previous items 63 | */ 64 | previousPage() { 65 | this.paginateTo(this.currentPage - 1); 66 | this.render(); 67 | } 68 | 69 | /** 70 | * go to specific page 71 | */ 72 | jumpToPage(page) { 73 | this.paginateTo(page); 74 | this.render(); 75 | } 76 | 77 | updateEvents() { 78 | this.afterEdit = new CustomEvent('afterEdit', { 79 | detail: { 80 | column: this.cell.column, 81 | row: this.cell.row, 82 | value: this.cell.value 83 | } 84 | }); 85 | this.beforeEdit = new CustomEvent('beforeEdit', { 86 | detail: { 87 | column: this.cell.column, 88 | row: this.cell.row 89 | } 90 | }) 91 | } 92 | 93 | /** 94 | * Jumps to a specific page. 95 | */ 96 | paginateTo(page) { 97 | if (this.totalPageCount < page || page <= 0) { 98 | return; 99 | } 100 | this.currentPage = page; 101 | this.items = this.allItems[page - 1]; 102 | 103 | return this.items; 104 | } 105 | 106 | 107 | /** 108 | * add input in table cell with it's value 109 | * @param {Event} event 110 | */ 111 | edit(row, column) { 112 | this.cell = {} 113 | this.cell.row = row; 114 | this.cell.column = column; 115 | this.updateEvents(); 116 | this.el.dispatchEvent(this.beforeEdit); 117 | 118 | const cell = event.target; 119 | const input = document.createElement('input'); 120 | const data = cell.innerText; 121 | input.classList.add('input', 'is-tiny', 'no-marginBottom'); 122 | input.value = data; 123 | cell.innerText = ''; 124 | cell.appendChild(input); 125 | input.focus(); 126 | input.addEventListener('blur', this.removeInput.bind(this, input, row, column)); 127 | } 128 | 129 | /** 130 | * remove the input and update the cell with value 131 | * @param {Element} input 132 | * @param {Node} cell 133 | */ 134 | removeInput(input, row, column) { 135 | this.cell.value = input.value; 136 | const flatItems = this.allItems.reduce((a, b) => a.concat(b), []); 137 | const findRow = (item) => item.id === row; 138 | const currentRaw = flatItems.find(findRow); 139 | currentRaw[column] = this.cell.value; 140 | this.render(); 141 | this.updateEvents(); 142 | this.el.dispatchEvent(this.afterEdit); 143 | } 144 | 145 | /** 146 | * Chunks the items into groups containing a specific number of items. 147 | */ 148 | _chunk(count) { 149 | // No Pagination required. 150 | if (count <= 0) { 151 | this.allItems = this.items; 152 | return; 153 | } 154 | 155 | const length = this.items.length; 156 | for (let i = 0; i < length; i += count) { 157 | this.allItems.push(this.items.slice(i, i + count)); 158 | } 159 | 160 | this.items = this.allItems[0]; 161 | } 162 | 163 | /** 164 | * Converts table columns and rows into objects. 165 | */ 166 | _normalizeTableData() { 167 | const rows = toArray(this.el.tBodies[0].rows); 168 | if (this.el.tHead) { 169 | this.columns = toArray(this.el.tHead.rows[0].cells); 170 | } else { 171 | this.columns = toArray(rows[0].cells); 172 | } 173 | this.columns = this.columns.map((cell) => cell.innerText.toLowerCase()); 174 | return rows.map((row, index) => { 175 | const rowData = { id: index }; 176 | toArray(row.cells).forEach((cell, index) => { 177 | rowData[this.columns[index]] = cell.innerText; 178 | }); 179 | return rowData; 180 | }); 181 | } 182 | } -------------------------------------------------------------------------------- /extensions/navbar/src/navbar.js: -------------------------------------------------------------------------------- 1 | import select from '../../_utils/select'; 2 | import debounce from '../../_utils/debounce'; 3 | import Dropdown from '../../dropdown/src/dropdown'; 4 | 5 | class Navbar { 6 | static defaults = { 7 | breakpoint: 500, 8 | hideMenuTolerance: 10 9 | }; 10 | 11 | constructor (el, settings) { 12 | this.el = select(el); 13 | this.settings = { 14 | ...Navbar.defaults, 15 | ...settings 16 | }; 17 | this.init(); 18 | } 19 | 20 | init () { 21 | this.wrapper = this.el.querySelector('[data-nav-items]'); 22 | this.menu = this.el.querySelector('[data-nav-menu]'); 23 | this.dropdownEl = this.el.querySelector('[data-nav-dropdown]'); 24 | this.items = Array.from(this.wrapper.children); 25 | this.menuItems = []; 26 | this.navbarItems = this.getPriorityOrder(); 27 | this.lastWindowSize = window.innerWidth; 28 | this.lastWindowScroll = window.scrollY; 29 | this.initEvents(); 30 | this.initDropdowns(); 31 | this.updateMenu(); 32 | } 33 | 34 | initDropdowns () { 35 | this.dropdown = new Dropdown( 36 | this.dropdownEl, 37 | this.dropdownEl.querySelector('.dropdown-menu'), 38 | { hideWhenClickOut: true } 39 | ); 40 | this.dropdowns = Array.from(this.wrapper.querySelectorAll('.dropdown')); 41 | this.dropdowns = this.dropdowns.map((dropdown) => { 42 | return new Dropdown( 43 | dropdown, 44 | dropdown.querySelector('.dropdown-menu'), 45 | { hideWhenClickOut: true } 46 | ); // eslint-disable-line 47 | }); 48 | } 49 | 50 | initEvents () { 51 | document.addEventListener('DOMContentLoaded', () => { 52 | setTimeout(this.updateMenu.bind(this), 100); 53 | }); 54 | window.addEventListener('resize', debounce((event) => { 55 | this.updateMenu(); 56 | }), { 57 | passive: true 58 | }); 59 | window.addEventListener('scroll', debounce((event) => { 60 | this.updateFixed(); 61 | }), { 62 | passive: true 63 | }); 64 | } 65 | 66 | updateFixed () { 67 | const currentScroll = window.scrollY; 68 | const mode = this.lastWindowScroll < currentScroll ? 'down' : 'up'; 69 | const tolerance = currentScroll - this.lastWindowScroll > this.settings.hideMenuTolerance; 70 | 71 | if (mode === 'down' && tolerance) { 72 | this.el.classList.add('is-hidden'); 73 | this.dropdowns.forEach(dropdown => dropdown.hide()); 74 | this.dropdown.hide(); 75 | } 76 | 77 | if (mode === 'up') { 78 | this.el.classList.remove('is-hidden'); 79 | } 80 | this.lastWindowScroll = currentScroll; 81 | } 82 | 83 | getPriorityOrder () { 84 | let lowPriority = []; 85 | let mediumPriority = []; 86 | let highPriority = []; 87 | 88 | this.items.forEach((item) => { 89 | let priority = item.dataset.navPriority; 90 | if (!priority) lowPriority.push(item); 91 | if (priority === 'low') lowPriority.push(item); 92 | if (priority === 'medium') mediumPriority.push(item); 93 | if (priority === 'high') highPriority.push(item); 94 | }); 95 | 96 | return lowPriority.concat(mediumPriority, highPriority); 97 | } 98 | 99 | isContained () { 100 | let itemsWidth = 0; 101 | let wrapperWidth = this.wrapper.clientWidth; 102 | 103 | this.navbarItems.forEach((item) => { 104 | itemsWidth += item.clientWidth; 105 | }); 106 | 107 | return wrapperWidth >= itemsWidth; 108 | } 109 | 110 | isMinimizing () { 111 | return this.lastWindowSize >= window.innerWidth; 112 | } 113 | 114 | getBeforeElementIndex (item) { 115 | const itemIndex = this.items.indexOf(item); 116 | const maxElements = this.items.length - 1; 117 | let outputIndex = itemIndex + 1; 118 | while (outputIndex <= maxElements) { 119 | if (this.items[outputIndex].parentNode === this.wrapper) { 120 | return outputIndex; 121 | } 122 | outputIndex++; 123 | } 124 | return false; 125 | } 126 | 127 | moveToMenu () { 128 | const item = this.navbarItems.shift(); 129 | item.classList.remove('navbar-item'); 130 | item.classList.add('dropdown-item'); 131 | this.menuItems.push(item); 132 | this.menu.appendChild(item); 133 | } 134 | 135 | moveToNavbar () { 136 | const item = this.menuItems.pop(); 137 | item.classList.remove('dropdown-item'); 138 | item.classList.add('navbar-item'); 139 | this.navbarItems.unshift(item); 140 | 141 | const beforeIndex = this.getBeforeElementIndex(item); 142 | if (beforeIndex) { 143 | this.wrapper.insertBefore(item, this.items[beforeIndex]); 144 | return; 145 | } 146 | this.wrapper.appendChild(item); 147 | } 148 | 149 | updateMenu () { 150 | if (window.matchMedia(`(max-width: ${this.settings.breakpoint}px)`).matches) { 151 | const length = this.navbarItems.length; 152 | for (let index = 0; index < length; index++) { 153 | this.moveToMenu(); 154 | } 155 | return; 156 | } 157 | 158 | const minimizing = this.isMinimizing(); 159 | 160 | if (!this.isContained() && minimizing) { 161 | this.moveToMenu(); 162 | } 163 | 164 | if (!minimizing && !!this.menuItems.length) { 165 | this.moveToNavbar(); 166 | } 167 | 168 | this.lastWindowSize = window.innerWidth; 169 | 170 | if (!this.isContained()) { 171 | this.updateMenu(); 172 | } 173 | 174 | if (!this.menuItems.length) { 175 | this.dropdown.el.style.display = 'none'; 176 | this.dropdown.hide(); 177 | } 178 | 179 | if (this.menuItems.length) { 180 | this.dropdown.el.style.display = ''; 181 | } 182 | } 183 | } 184 | 185 | export default Navbar; 186 | -------------------------------------------------------------------------------- /extensions/datepicker/src/datepicker.js: -------------------------------------------------------------------------------- 1 | import select from '../../_utils/select' 2 | import Dropdown from '../../dropdown/src/dropdown'; 3 | import { 4 | endOfMonth, 5 | startOfMonth, 6 | getYear, 7 | getMonth, 8 | format, 9 | parse, 10 | addMonths 11 | } from 'date-fns/esm'; 12 | 13 | class Datepicker { 14 | static defaults = { 15 | dateFormat: 'dd/MM/yyyy', 16 | days: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 17 | months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] 18 | }; 19 | 20 | constructor (el, settings) { 21 | this.el = select(el); 22 | this.settings = { 23 | ...Datepicker.defaults, 24 | ...settings 25 | }; 26 | this.init(); 27 | } 28 | 29 | init () { 30 | this.currentDate = new Date(); 31 | 32 | // create datepicker wrapper 33 | this.wrapper = document.createElement('div'); 34 | this.dropdownMenu = document.createElement('div'); 35 | this.datepickerControl = document.createElement('div'); 36 | this.table = document.createElement('table'); 37 | this.yearSelector = document.createElement('input'); 38 | this.monthSelector = document.createElement('select'); 39 | 40 | this.wrapper.classList.add('dropdown'); 41 | this.dropdownMenu.classList.add('dropdown-menu'); 42 | this.datepickerControl.classList.add('datepicker-control') 43 | this.table.classList.add('calendar'); 44 | 45 | // build the calendar nodes structure 46 | this.settings.months.forEach((month, index) => { 47 | let option = document.createElement('option'); 48 | option.value = index; 49 | option.innerHTML = month; 50 | this.monthSelector.appendChild(option); 51 | }) 52 | 53 | // append the calendar to DOM 54 | this.datepickerControl.appendChild(this.monthSelector); 55 | this.datepickerControl.appendChild(this.yearSelector); 56 | this.dropdownMenu.appendChild(this.datepickerControl); 57 | this.dropdownMenu.appendChild(this.table); 58 | this.wrapper.appendChild(this.dropdownMenu); 59 | this.el.parentNode.insertBefore(this.wrapper, this.el); 60 | this.wrapper.appendChild(this.el); 61 | 62 | // start 63 | this.dropdown = new Dropdown(this.el, this.dropdownMenu); 64 | this.update(); 65 | this.initEvents(); 66 | } 67 | 68 | initEvents () { 69 | this.monthSelector.addEventListener('change', (e) => { 70 | this.setMonth(e.target.value); 71 | this.update(); 72 | }); 73 | this.yearSelector.addEventListener('change', (e) => { 74 | this.setYear(e.target.value); 75 | this.update(); 76 | }); 77 | this.el.addEventListener('change', (e) => { 78 | this.setDate(e.target.value); 79 | this.update(); 80 | }); 81 | } 82 | 83 | setDay (day) { 84 | this.currentDate.setDate(day); 85 | } 86 | 87 | setYear (year) { 88 | this.currentDate.setYear(year); 89 | } 90 | 91 | setMonth (month) { 92 | this.currentDate.setMonth(month); 93 | } 94 | 95 | setDate (date) { 96 | this.currentDate = parse(date, this.settings.dateFormat, new Date()); 97 | } 98 | 99 | update () { 100 | this.el.value = this.getFormatedDate(this.currentDate); 101 | this.updateTableDate(); 102 | } 103 | 104 | updateTableDate () { 105 | this.monthSelector.value = getMonth(this.currentDate); 106 | this.yearSelector.value = getYear(this.currentDate); 107 | const dayOfWeek = startOfMonth(this.currentDate).getDay(); 108 | const lastDayOfTheCurrentMonth = endOfMonth(this.currentDate).getDate(); 109 | const lastDayOfThePreviousMonth = endOfMonth(addMonths(this.currentDate, -1)).getDate(); 110 | const currentDay = this.currentDate.getDate(); 111 | 112 | // clean calender 113 | this.table.innerHTML = ''; 114 | 115 | let header = document.createElement('tr'); 116 | for (let i = 0; i < 7; i++) { 117 | this._createCell(header, this.settings.days[i], 'th'); 118 | this.table.appendChild(header); 119 | } 120 | 121 | let day = lastDayOfThePreviousMonth - dayOfWeek + 1; 122 | let limit = 0; 123 | let mode = 'is-previous'; 124 | let active = []; 125 | for (let rowNumber = 0; rowNumber < 6; rowNumber++) { 126 | limit = rowNumber > 0 ? lastDayOfTheCurrentMonth : lastDayOfThePreviousMonth; 127 | let row = document.createElement('tr'); 128 | for (let i = 0; i < this.settings.days.length; i++) { 129 | if (day > limit) { 130 | day = 1; 131 | mode = mode === 'is-previous' ? 'is-current' : 'is-following'; 132 | } 133 | if (mode === 'is-current' && currentDay === day) { 134 | active = ['is-active'] 135 | } else { 136 | active = [] 137 | } 138 | this._createCell(row, day, 'td', [mode].concat(active)); 139 | this.table.appendChild(row); 140 | day++; 141 | } 142 | } 143 | } 144 | 145 | handleCellClick (e) { 146 | const cell = event.target; 147 | const currentMonth = this.currentDate.getMonth(); 148 | 149 | if (cell.classList.contains('is-previous')) { 150 | this.setMonth(currentMonth - 1); 151 | } 152 | if (cell.classList.contains('is-following')) { 153 | this.setMonth(currentMonth + 1); 154 | } 155 | this.setDay(cell.innerHTML); 156 | this.update(); 157 | } 158 | 159 | getFormatedDate (date) { 160 | return format(date, this.settings.dateFormat); 161 | } 162 | 163 | _createCell (row, data, type, extraClass = null) { 164 | let cell = document.createElement(type); 165 | if (extraClass) { 166 | cell.classList.add(...extraClass); 167 | } 168 | if (type === 'td') { 169 | cell.addEventListener('click', this.handleCellClick.bind(this)); 170 | } 171 | cell.innerHTML = data; 172 | row.appendChild(cell); 173 | } 174 | } 175 | 176 | export default Datepicker; 177 | -------------------------------------------------------------------------------- /src/core/normalize.styl: -------------------------------------------------------------------------------- 1 | /** 2 | * Using normalize.css v8.0.0 3 | */ 4 | 5 | 6 | /* Document 7 | ========================================================================== */ 8 | 9 | /** 10 | * Prevent adjustments of font size after orientation changes in iOS. 11 | */ 12 | 13 | html 14 | -webkit-text-size-adjust: 100% 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body 24 | margin: 0 25 | 26 | 27 | /* Grouping content 28 | ========================================================================== */ 29 | 30 | /** 31 | * 1. Add the correct box sizing in Firefox. 32 | * 2. Show the overflow in Edge and IE. 33 | */ 34 | 35 | hr 36 | box-sizing: content-box /* 1 */ 37 | height: 0 /* 1 */ 38 | overflow: visible /* 2 */ 39 | 40 | /** 41 | * 1. Correct the inheritance and scaling of font size in all browsers. 42 | * 2. Correct the odd `em` font sizing in all browsers. 43 | */ 44 | 45 | pre 46 | font-family: monospace, monospace /* 1 */ 47 | font-size: 1em /* 2 */ 48 | 49 | /* Text-level semantics 50 | ========================================================================== */ 51 | 52 | /** 53 | * Remove the gray background on active links in IE 10. 54 | */ 55 | 56 | a 57 | background-color: transparent 58 | 59 | /** 60 | * 1. Remove the bottom border in Chrome 57- 61 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 62 | */ 63 | 64 | abbr[title] 65 | border-bottom: none /* 1 */ 66 | text-decoration: underline /* 2 */ 67 | text-decoration: underline dotted /* 2 */ 68 | 69 | /** 70 | * Add the correct font weight in Chrome, Edge, and Safari. 71 | */ 72 | 73 | b, 74 | strong 75 | font-weight: bolder 76 | 77 | /** 78 | * 1. Correct the inheritance and scaling of font size in all browsers. 79 | * 2. Correct the odd `em` font sizing in all browsers. 80 | */ 81 | 82 | code, 83 | kbd, 84 | samp 85 | font-family: monospace, monospace /* 1 */ 86 | font-size: 1em /* 2 */ 87 | 88 | /** 89 | * Add the correct font size in all browsers. 90 | */ 91 | 92 | small 93 | font-size: 80% 94 | 95 | /** 96 | * Prevent `sub` and `sup` elements from affecting the line height in 97 | * all browsers. 98 | */ 99 | 100 | sub, 101 | sup 102 | font-size: 75% 103 | line-height: 0 104 | position: relative 105 | vertical-align: baseline 106 | 107 | sub 108 | bottom: -0.25em 109 | 110 | sup 111 | top: -0.5em 112 | 113 | /* Embedded content 114 | ========================================================================== */ 115 | 116 | /** 117 | * Remove the border on images inside links in IE 10. 118 | */ 119 | 120 | img 121 | border-style: none 122 | 123 | /* Forms 124 | ========================================================================== */ 125 | 126 | /** 127 | * 1. Change the font styles in all browsers. 128 | * 2. Remove the margin in Firefox and Safari. 129 | */ 130 | 131 | button, 132 | input, 133 | optgroup, 134 | select, 135 | textarea 136 | font-family: inherit /* 1 */ 137 | font-size: 100% /* 1 */ 138 | line-height: 1.15 /* 1 */ 139 | margin: 0 /* 2 */ 140 | 141 | /** 142 | * Show the overflow in IE. 143 | * 1. Show the overflow in Edge. 144 | */ 145 | 146 | button, 147 | input /* 1 */ 148 | overflow: visible 149 | 150 | /** 151 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 152 | * 1. Remove the inheritance of text transform in Firefox. 153 | */ 154 | 155 | button, 156 | select /* 1 */ 157 | text-transform: none 158 | 159 | /** 160 | * Correct the inability to style clickable types in iOS and Safari. 161 | */ 162 | 163 | button, 164 | [type="button"], 165 | [type="reset"], 166 | [type="submit"] 167 | -webkit-appearance: button 168 | 169 | /** 170 | * Remove the inner border and padding in Firefox. 171 | */ 172 | 173 | button::-moz-focus-inner, 174 | [type="button"]::-moz-focus-inner, 175 | [type="reset"]::-moz-focus-inner, 176 | [type="submit"]::-moz-focus-inner 177 | border-style: none 178 | padding: 0 179 | 180 | /** 181 | * Restore the focus styles unset by the previous rule. 182 | */ 183 | 184 | button:-moz-focusring, 185 | [type="button"]:-moz-focusring, 186 | [type="reset"]:-moz-focusring, 187 | [type="submit"]:-moz-focusring 188 | outline: 1px dotted ButtonText 189 | 190 | /** 191 | * Correct the padding in Firefox. 192 | */ 193 | 194 | fieldset 195 | padding: 0.35em 0.75em 0.625em 196 | 197 | /** 198 | * 1. Correct the text wrapping in Edge and IE. 199 | * 2. Correct the color inheritance from `fieldset` elements in IE. 200 | * 3. Remove the padding so developers are not caught out when they zero out 201 | * `fieldset` elements in all browsers. 202 | */ 203 | 204 | legend 205 | box-sizing: border-box /* 1 */ 206 | color: inherit /* 2 */ 207 | display: table /* 1 */ 208 | max-width: 100% /* 1 */ 209 | padding: 0 /* 3 */ 210 | white-space: normal /* 1 */ 211 | 212 | /** 213 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 214 | */ 215 | 216 | progress 217 | vertical-align: baseline 218 | 219 | /** 220 | * Remove the default vertical scrollbar in IE 10+. 221 | */ 222 | 223 | textarea 224 | overflow: auto 225 | 226 | /** 227 | * 1. Add the correct box sizing in IE 10. 228 | * 2. Remove the padding in IE 10. 229 | */ 230 | 231 | [type="checkbox"], 232 | [type="radio"] 233 | box-sizing: border-box /* 1 */ 234 | padding: 0 /* 2 */ 235 | 236 | /** 237 | * Correct the cursor style of increment and decrement buttons in Chrome. 238 | */ 239 | 240 | [type="number"]::-webkit-inner-spin-button, 241 | [type="number"]::-webkit-outer-spin-button 242 | height: auto 243 | 244 | /** 245 | * 1. Correct the odd appearance in Chrome and Safari. 246 | * 2. Correct the outline style in Safari. 247 | */ 248 | 249 | [type="search"] 250 | -webkit-appearance: textfield /* 1 */ 251 | outline-offset: -2px /* 2 */ 252 | 253 | /** 254 | * Remove the inner padding in Chrome and Safari on macOS. 255 | */ 256 | 257 | [type="search"]::-webkit-search-decoration 258 | -webkit-appearance: none 259 | 260 | /** 261 | * 1. Correct the inability to style clickable types in iOS and Safari. 262 | * 2. Change font properties to `inherit` in Safari. 263 | */ 264 | 265 | ::-webkit-file-upload-button 266 | -webkit-appearance: button /* 1 */ 267 | font: inherit /* 2 */ 268 | 269 | /* Interactive 270 | ========================================================================== */ 271 | 272 | /* 273 | * Add the correct display in Edge, IE 10+, and Firefox. 274 | */ 275 | 276 | details 277 | display: block 278 | 279 | /* 280 | * Add the correct display in all browsers. 281 | */ 282 | 283 | summary 284 | display: list-item 285 | 286 | /* Misc 287 | ========================================================================== */ 288 | 289 | /** 290 | * Add the correct display in IE 10+. 291 | */ 292 | 293 | template 294 | display: none 295 | 296 | /** 297 | * Add the correct display in IE 10. 298 | */ 299 | 300 | [hidden] 301 | display: none -------------------------------------------------------------------------------- /extensions/accordion/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Blexar Accordion 8 | 9 | 10 | 11 |
12 |
13 |

Blexar Accordion

14 |

An accordion allows users to toggle the display of sections of content

15 |
16 |
17 |
18 |

Default

19 |
20 |
21 |
    22 |
  • 23 | 24 | 25 | Title 1 26 | 27 |
    28 |

    Lorem ipsum dolor sit, amet consectetur adipisicing elit. Repudiandae et, labore non soluta quaerat blanditiis architecto nesciunt? Ut magni accusantium nesciunt molestiae accusamus inventore eligendi dolorem quaerat quisquam! Voluptatum, provident?

    29 |

     

    30 | click 31 |
    32 |
  • 33 | 34 |
  • 35 | 36 | 37 | Title 2 38 | 39 |
    40 |

    Lorem ipsum dolor sit, amet consectetur adipisicing elit. Repudiandae et, labore non soluta quaerat blanditiis architecto nesciunt? Ut magni accusantium nesciunt molestiae accusamus inventore eligendi dolorem quaerat quisquam! Voluptatum, provident?

    41 |
    42 |
  • 43 | 44 |
  • 45 | 46 | 47 | Title 3 48 | 49 |
    50 |

    Lorem ipsum dolor sit, amet consectetur adipisicing elit. Repudiandae et, labore non soluta quaerat blanditiis architecto nesciunt? Ut magni accusantium nesciunt molestiae accusamus inventore eligendi dolorem quaerat quisquam! Voluptatum, provident?

    51 |
    52 |
  • 53 |
54 |
55 |
56 |

Clear

57 |
58 |
59 |
    60 |
  • item 1 61 |
    62 |
    63 |
    64 |

    65 | Lorem ipsum dolor sit, amet consectetur adipisicing elit. Repudiandae et, labore non soluta quaerat blanditiis architecto nesciunt? Ut magni accusantium nesciunt molestiae accusamus inventore eligendi dolorem quaerat quisquam! Voluptatum, provident? 66 |

    67 |
    68 |
    69 |
  • 70 |
  • item 2 71 |
    72 |

    73 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod, voluptatibus sequi nulla nostrum quae animi molestias dolor praesentium itaque a dolore dolorem aliquam placeat earum adipisci quos totam molestiae. Commodi. 74 |

    75 |
    76 |
  • 77 |
  • item 3 78 |
    79 |

    80 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo et officiis rerum explicabo, veniam vel voluptatum. Commodi enim ullam voluptates error id, eligendi, culpa laborum aut neque dolores quasi! Aliquam. 81 |

    82 |

    83 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Culpa nobis minus magnam sed sint quas, enim officia aspernatur qui, voluptatem adipisci! Modi eum quam veniam iusto vitae obcaecati? Ratione, sapiente? 84 |

    85 |

    86 | Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cupiditate eaque praesentium aperiam fuga adipisci laborum est, dignissimos sit fugit consectetur alias vero quaerat eligendi libero numquam? Qui veritatis nihil ducimus? 87 |

    88 |
    89 |
  • 90 |
91 |
92 |
93 |

Nested accordions

94 |
95 |
96 |
    97 |
  • 98 | 99 | item 1 100 | 101 |
    102 |
      103 |
    • 104 | 105 | inner item 1 106 | 107 |
      108 |

      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Repudiandae et, labore non soluta quaerat blanditiis architecto nesciunt? Ut magni accusantium nesciunt molestiae accusamus inventore eligendi dolorem quaerat quisquam! Voluptatum, provident?

      109 |
      110 |
    • 111 |
    • 112 | 113 | inner item 2 114 | 115 |
      116 |

      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Repudiandae et, labore non soluta quaerat blanditiis architecto nesciunt? Ut magni accusantium nesciunt molestiae accusamus inventore eligendi dolorem quaerat quisquam! Voluptatum, provident?

      117 |
      118 |
    • 119 |
    120 |
    121 |
  • 122 |
  • 123 | item 2 124 |
    125 |

    Awesome content!

    126 |
    127 |
  • 128 |
  • 129 | item 3 130 |
    131 |

    Awesome content!

    132 |
    133 |
  • 134 |
135 |
136 |
137 |
138 | 139 | 140 | 146 | 147 | -------------------------------------------------------------------------------- /extensions/table/src/table.js: -------------------------------------------------------------------------------- 1 | import select from '../../_utils/select'; 2 | import wrap from '../../_utils/wrap'; 3 | import toArray from '../../_utils/toArray'; 4 | import debounce from '../../_utils/debounce'; 5 | 6 | import Sortable from './sortable'; 7 | import Paginator from './paginator'; 8 | 9 | class Table { 10 | static defaults = { 11 | fixedHeader: false, 12 | pagination: true, 13 | sortable: true, 14 | editable: false, 15 | density: false, 16 | perPage: 10 17 | } 18 | constructor(el, settings) { 19 | this.el = select(el); 20 | this.settings = { 21 | ...Table.defaults, 22 | ...settings 23 | } 24 | this.init(); 25 | } 26 | 27 | /** 28 | * init all table extensions 29 | */ 30 | init() { 31 | this.paginator = new Paginator(this.el, { 32 | perPage: this.settings.perPage, 33 | editable: this.settings.editable 34 | }); 35 | this.sortable = new Sortable(this.el, this.paginator); 36 | this.scroll = window.scrollY; 37 | this.initWrapper(); 38 | if (this.settings.pagination) this.initPagination(); 39 | if (this.settings.sortable) this.initSortable(); 40 | if (this.settings.density) this.initDensity(); 41 | if (this.settings.fixedHeader) this.initFixedHeader(); 42 | } 43 | 44 | /** 45 | * add wrapper around the table 46 | */ 47 | initWrapper() { 48 | this.wrapper = document.createElement('div'); 49 | this.wrapper.classList.add('table-wrapper'); 50 | wrap(this.el, this.wrapper); 51 | } 52 | 53 | /** 54 | * init fixed header when scroll 55 | */ 56 | initFixedHeader() { 57 | this.header = this.el.querySelector('thead'); 58 | this.ticking = false; 59 | this.updateHeaderSize(); 60 | window.addEventListener('scroll', () => { 61 | this.scroll = window.scrollY; 62 | if (!this.ticking) { 63 | window.requestAnimationFrame(() => { 64 | this.updateHeaderState(); 65 | this.ticking = false; 66 | }); 67 | } 68 | this.ticking = true; 69 | }, { 70 | passive: true 71 | }); 72 | window.addEventListener('resize', 73 | debounce(this.updateHeaderSize.bind(this)), 74 | { passive: true } 75 | ); 76 | } 77 | 78 | /** 79 | * init ability to sort table elements 80 | */ 81 | initSortable() { 82 | this.lastSort = ''; 83 | this.headers = toArray(this.el.querySelectorAll('thead th')); 84 | this.titles = this.headers.map((header) => header.innerHTML.toLowerCase()); 85 | this.sortButtons = []; 86 | this.headers.forEach((header) => { 87 | header.insertAdjacentHTML('beforeend', 88 | `` 93 | ); 94 | this.sortButtons.push(header.querySelector('button')); 95 | }); 96 | 97 | this.sortButtons.forEach((button, index) => { 98 | button.addEventListener('click', () => { 99 | let direction = this.lastSort.button === button 100 | ? this.lastSort.dir === 'asc' ? 'desc' : 'asc' 101 | : 'asc'; 102 | this.lastSort = { 103 | button: button, 104 | dir: direction 105 | }; 106 | this.sortable.sortBy(this.titles[index].toString(), direction); 107 | this.sortButtons.forEach((btn) => { 108 | btn.classList.remove('is-active', 'is-desc'); 109 | }); 110 | button.classList.add('is-active'); 111 | if (direction === 'desc') button.classList.add('is-desc'); 112 | }); 113 | }); 114 | } 115 | 116 | /** 117 | * init table pagination 118 | */ 119 | initPagination() { 120 | this.pagination = {}; 121 | this.pagination.row = document.createElement('nav'); 122 | this.pagination.row.classList.add('pagination'); 123 | 124 | for (let pageNumber = 1; pageNumber <= this.paginator.totalPageCount; pageNumber++) { 125 | const callback = () => { 126 | this.paginator.jumpToPage(pageNumber); 127 | this.updateHeaderSize(); 128 | } 129 | const button = document.createElement('button'); 130 | button.classList.add('pagination-item'); 131 | button.innerText = pageNumber; 132 | button.addEventListener('click', callback); 133 | this.pagination.row.appendChild(button); 134 | } 135 | 136 | this.pagination.row.insertAdjacentHTML('afterbegin', ` 137 | 142 | `); 143 | this.pagination.row.insertAdjacentHTML('beforeend', ` 144 | 149 | `); 150 | 151 | this.wrapper.appendChild(this.pagination.row); 152 | 153 | this.pagination.previous = this.wrapper.querySelector('.pagination-prev'); 154 | this.pagination.next = this.wrapper.querySelector('.pagination-next'); 155 | 156 | this.pagination.previous.addEventListener('click', () => { 157 | this.paginator.previousPage(); 158 | this.updateHeaderSize(); 159 | }); 160 | this.pagination.next.addEventListener('click', () => { 161 | this.paginator.nextPage(); 162 | this.updateHeaderSize(); 163 | }); 164 | } 165 | 166 | /** 167 | * init display density 168 | */ 169 | initDensity() { 170 | this.density = {}; 171 | this.wrapper.insertAdjacentHTML('afterbegin', ` 172 |
173 | 178 | 183 | 188 |
189 | `); 190 | 191 | this.density.small = this.wrapper.querySelector('.density-small'); 192 | this.density.medium = this.wrapper.querySelector('.density-medium'); 193 | this.density.large = this.wrapper.querySelector('.density-large'); 194 | this.density.small.addEventListener('click', () => this.applyDensity('small')); 195 | this.density.medium.addEventListener('click', () => this.applyDensity('medium')); 196 | this.density.large.addEventListener('click', () => this.applyDensity('large')); 197 | } 198 | 199 | applyDensity(density) { 200 | Object.keys(this.density).forEach((key) => { 201 | this.density[key].classList.remove('is-active'); 202 | }); 203 | this.density[density].classList.add('is-active'); 204 | this.el.classList.remove('is-large', 'is-medium', 'is-small'); 205 | this.el.classList.add(`is-${density}`); 206 | if (this.settings.fixedHeader) { 207 | this.updateHeaderSize(); 208 | this.updateHeaderState(); 209 | } 210 | } 211 | /** 212 | * update header position 213 | */ 214 | updateHeaderState() { 215 | this.header.style.willChange = 'transform'; 216 | const headerPosition = this.scroll - this.tableTop; 217 | if (this.scroll >= this.tableBottom - this.headerHeight) { 218 | return; 219 | } 220 | if (this.scroll >= this.tableTop) { 221 | this.header.style.transform = `translate3d(0, ${headerPosition}px, 0)`; 222 | return; 223 | } 224 | this.header.style.willChange = ''; 225 | this.header.style.transform = `translate3d(0, 0, 0)`; 226 | } 227 | 228 | /** 229 | * update header size 230 | */ 231 | updateHeaderSize() { 232 | this.tableTop = this.el.getBoundingClientRect().top + window.scrollY; 233 | this.tableBottom = this.el.getBoundingClientRect().bottom + window.scrollY; 234 | this.headerHeight = this.header.getBoundingClientRect().height; 235 | } 236 | } 237 | 238 | export default Table; 239 | -------------------------------------------------------------------------------- /extensions/select/src/select.js: -------------------------------------------------------------------------------- 1 | import Dropdown from '../../dropdown/src/dropdown'; 2 | import select from '../../_utils/select'; 3 | import debounce from '../../_utils/debounce'; 4 | 5 | class Select { 6 | static defaults = { 7 | data: null, 8 | multiple: false 9 | } 10 | constructor (selector, settings) { 11 | this.el = select(selector); 12 | this.settings = { 13 | ...Select.defaults, 14 | ...settings 15 | } 16 | this.init(); 17 | } 18 | 19 | get value () { 20 | if (this.settings.multiple) { 21 | return this.results.map((opt) => opt.value); 22 | } 23 | return this.el.value; 24 | } 25 | 26 | init () { 27 | this._initSelect(); 28 | this._initData(); 29 | this._initMenu(); 30 | this._initEvents(); 31 | } 32 | 33 | _initSelect () { 34 | this.select = document.createElement('div'); 35 | this.input = document.createElement('input'); 36 | 37 | const currentClasses = this.el.classList ? Array.from(this.el.classList) : ['']; 38 | this.select.classList.add('select', ...currentClasses); 39 | this.input.classList.add('select-input'); 40 | this.el.classList.add('is-hidden'); 41 | 42 | this.el.parentNode.insertBefore(this.select, this.el); 43 | this.select.appendChild(this.el); 44 | this.select.appendChild(this.input); 45 | if (this.settings.multiple || this.el.multiple) { 46 | this.settings.multiple = true; 47 | this.results = []; 48 | this.labels = document.createElement('div'); 49 | this.labels.classList.add('select-labels'); 50 | this.select.appendChild(this.labels); 51 | this.el.multiple = true; 52 | } 53 | if (this.settings.data !== null) { 54 | this._generateSelectFromData(); 55 | } 56 | } 57 | 58 | _initData () { 59 | if (this.settings.data !== null) { 60 | this.data = this.settings.data; 61 | return; 62 | } 63 | const optionsGroup = Array.from(this.el.querySelectorAll('optgroup')); 64 | const options = Array.from(this.el.querySelectorAll(':scope >option')); 65 | this.data = optionsGroup.map(group => { 66 | const groupData = { text: group.label }; 67 | const options = Array.from(group.querySelectorAll(':scope >option')); 68 | groupData.children = options.map(option => { 69 | return { 70 | text: option.innerHTML, 71 | value: option.value 72 | } 73 | }); 74 | return groupData; 75 | }); 76 | this.data = this.data.concat(options.map(option => { 77 | return { 78 | text: option.innerHTML, 79 | value: option.value 80 | } 81 | })); 82 | } 83 | 84 | _initMenu () { 85 | this.isMenuVisible = false; 86 | this.options = []; 87 | this.menu = document.createElement('div'); 88 | this.list = document.createElement('ul'); 89 | 90 | this.menu.classList.add('select-menu'); 91 | this.list.classList.add('select-list'); 92 | 93 | // generate options based on data object 94 | let id = 0; 95 | this.data.forEach(el => { 96 | const item = document.createElement('li'); 97 | item.classList.add('select-item'); 98 | this.list.appendChild(item); 99 | if (el.children) { 100 | const childTitle = document.createElement('label'); 101 | const childMenu = document.createElement('ul'); 102 | childTitle.classList.add('select-childTitle'); 103 | childMenu.classList.add('select-childMenu'); 104 | item.classList.add('is-group'); 105 | item.appendChild(childTitle); 106 | item.appendChild(childMenu); 107 | 108 | childTitle.innerText = el.text; 109 | el.children.forEach((child) => { 110 | const childItem = document.createElement('li'); 111 | childItem.classList.add('select-childItem'); 112 | childMenu.appendChild(childItem); 113 | childItem.innerText = child.text; 114 | this.options.push({ 115 | element: childItem, 116 | id: id++, 117 | text: child.text, 118 | value: child.value 119 | }); 120 | }); 121 | return; 122 | } 123 | item.innerText = el.text; 124 | this.options.push({ 125 | element: item, 126 | id: id++, 127 | text: el.text, 128 | value: el.value 129 | }); 130 | }); 131 | this.menu.appendChild(this.list); 132 | this.select.appendChild(this.menu); 133 | if (~this.el.selectedIndex) { 134 | this.selectOption(this.options.find(opt => opt.id === this.el.selectedIndex)); 135 | } 136 | this.dropdown = new Dropdown(this.select, this.menu, { 137 | hideWhenClickOut: true 138 | }); 139 | } 140 | 141 | _initEvents () { 142 | this.options.forEach(option => { 143 | option.element.addEventListener('click', () => { 144 | this.selectOption(option); 145 | }) 146 | }); 147 | this.input.addEventListener('input', () => { 148 | const filter = this.input.value.toUpperCase(); 149 | this.options.forEach(option => { 150 | if (option.text.toUpperCase().indexOf(filter) === -1) { 151 | option.element.style.display = 'none'; 152 | return; 153 | } 154 | option.element.style.display = ''; 155 | }); 156 | }); 157 | if (this.settings.multiple) { 158 | window.addEventListener('resize', debounce(this.updateSelectSize.bind(this))); 159 | } 160 | } 161 | 162 | _generateSelectFromData () { 163 | const frag = document.createDocumentFragment(); 164 | this.settings.data.forEach(option => { 165 | if (option.children) { 166 | const group = document.createElement('optgroup'); 167 | group.label = option.text; 168 | option.children.forEach(child => { 169 | const option = document.createElement('option'); 170 | option.innerText = child.text; 171 | option.value = child.value; 172 | group.appendChild(option); 173 | }); 174 | this.option.appendChild(group); 175 | return; 176 | } 177 | const optionElement = document.createElement('option'); 178 | optionElement.innerText = option.text; 179 | optionElement.value = option.value; 180 | frag.appendChild(optionElement); 181 | }); 182 | this.el.appendChild(frag); 183 | } 184 | 185 | selectOption (option) { 186 | // if (!option || this.el.selectedIndex === option.id) return; 187 | if (this.settings.multiple) { 188 | this.updateResults(option, this.el.item(option.id).selected); 189 | this.updateLabels(); 190 | this.el.dispatchEvent(new Event('change')); // eslint-disable-line 191 | return; 192 | } 193 | this.options.forEach((opt) => { 194 | opt.element.classList.remove('is-selected'); 195 | }) 196 | option.element.classList.add('is-selected'); 197 | this.el.selectedIndex = option.id; 198 | this.input.value = this.el[this.el.selectedIndex].innerText; 199 | this.el.dispatchEvent(new Event('change')); // eslint-disable-line 200 | } 201 | 202 | updateLabels () { 203 | this.labels.innerHTML = ''; 204 | this.results.forEach((result) => { 205 | const label = ` 206 |
207 | ${result.text} 208 | 209 | 210 | 211 | 212 | 213 |
` 214 | this.labels.insertAdjacentHTML('beforeEnd', label); 215 | this.updateSelectSize(); 216 | const close = this.labels.querySelector(`#close-${result.id}`); 217 | close.addEventListener('click', (event) => { 218 | event.preventDefault(); 219 | event.stopPropagation(); 220 | this.updateResults(result, true); 221 | this.updateLabels(); 222 | }); 223 | }); 224 | } 225 | 226 | updateSelectSize () { 227 | let labels = this.labels.offsetHeight; 228 | if (labels === 0) return; 229 | let border = window.getComputedStyle(this.select, null).getPropertyValue('border-width'); 230 | let borders = Number(border.slice(0, -2)) * 2; 231 | this.select.style.height = `${labels + borders}px`; 232 | } 233 | updateResults (result, remove) { 234 | if (remove) { 235 | this.el.item(result.id).selected = false; 236 | this.results.splice(this.results.indexOf(result), 1); 237 | result.element.classList.remove('is-selected'); 238 | return; 239 | } 240 | this.el.item(result.id).selected = true; 241 | this.results.push(result); 242 | result.element.classList.add('is-selected'); 243 | } 244 | } 245 | 246 | export default Select; 247 | -------------------------------------------------------------------------------- /extensions/slider/src/slider.js: -------------------------------------------------------------------------------- 1 | import { mixColors } from 'color-fns'; 2 | 3 | import select from '../../_utils/select'; 4 | import wrap from '../../_utils/wrap'; 5 | import call from '../../_utils/call'; 6 | import getClosestValue from '../../_utils/getClosestValue'; 7 | import stringToDOM from '../../_utils/stringToDOM'; 8 | 9 | 10 | /** 11 | * Slider class 12 | */ 13 | export default class Slider { 14 | constructor (selector, settings) { 15 | this.el = select(selector); 16 | this.settings = { 17 | ...Slider.defaults, 18 | ...settings 19 | }; 20 | this._init(); 21 | } 22 | 23 | /** 24 | * create new rang slider element 25 | * @param {String|HTMLElement} selector 26 | * @param {Object} settings 27 | */ 28 | static create (selector, settings) { 29 | Slider(selector, settings); 30 | } 31 | 32 | _init () { 33 | this.values = []; 34 | this.percentages = []; 35 | this.multiple = this.settings.handles.length > 1; 36 | this.min = Number(this.el.min) || Number(this.settings.min); 37 | this.max = Number(this.el.max) || Number(this.settings.max); 38 | this.step = Number(this.el.step) || Number(this.settings.step); 39 | if (this.settings.handles.length === 1) { 40 | this.settings.handles[0] = Number(this.el.value) || Number(this.settings.value); 41 | } 42 | this.settings.handles.sort(); 43 | if (this.settings.colorCode) { 44 | this.el.type = 'text'; 45 | } 46 | 47 | this._initElements(); 48 | if (this.settings.gradient) { 49 | this._initGradient(); 50 | } 51 | this._initEvents(); 52 | this.settings.handles.forEach((handle, index) => { 53 | this.activeHandle = index; 54 | this.update(handle); 55 | }) 56 | this.update(); 57 | } 58 | 59 | _initElements () { 60 | this.handles = []; 61 | this.labels = []; 62 | this.wrapper = document.createElement('div'); 63 | this.track = document.createElement('div'); 64 | 65 | this.wrapper.classList.add('slider'); 66 | this.wrapper.classList.toggle('is-editable', this.settings.editable); 67 | this.wrapper.classList.toggle('is-reverse', this.settings.reverse); 68 | if (this.settings.classes) { 69 | this.wrapper.classList.add(...this.settings.classes); 70 | } 71 | this.track.classList.add('slider-track'); 72 | this.el.classList.add('slider-input'); 73 | 74 | if (this.settings.handles.length === 1) { 75 | this.fill = document.createElement('div'); 76 | this.fill.classList.add('slider-fill'); 77 | this.track.appendChild(this.fill); 78 | } 79 | 80 | this.settings.handles.forEach((position, index) => { 81 | this.handles[index] = stringToDOM(`
`); 82 | if (this.settings.label) { 83 | this.labels[index] = stringToDOM(`
`) 84 | this.handles[index].appendChild(this.labels[index]); 85 | } 86 | this.handles[index].addEventListener('mousedown', this.select.bind(this), false); 87 | this.handles[index].addEventListener('touchstart', this.select.bind(this), false); 88 | this.track.appendChild(this.handles[index]); 89 | }); 90 | 91 | wrap(this.el, this.wrapper); 92 | this.wrapper.appendChild(this.track); 93 | call(this.settings.created, this); 94 | } 95 | 96 | _initGradient () { 97 | if (this.settings.gradient.length > 1) { 98 | this.track.style.backgroundImage = `linear-gradient(90deg, ${this.settings.gradient})`; 99 | this.gradient = this.settings.gradient; 100 | return; 101 | } 102 | this.track.style.backgroundImage = ''; 103 | this.track.style.backgroundColor = this.settings.gradient[0]; 104 | this.handles.forEach(handle => { 105 | handle.style.color = this.settings.gradient[0]; 106 | }); 107 | this.gradient = null; 108 | } 109 | 110 | _initEvents () { 111 | window.addEventListener('resize', () => { 112 | this.updateWidth(); 113 | this.update(undefined, true); 114 | }); 115 | if (this.settings.trackSlide) { 116 | this.track.addEventListener('mousedown', this.select.bind(this), false); 117 | this.track.addEventListener('touchstart', this.select.bind(this), false); 118 | } 119 | if (this.settings.editable && !this.settings.colorCode) { 120 | this.el.addEventListener('change', (evt) => { 121 | this.update(this.el.value); 122 | }, false); 123 | } 124 | } 125 | 126 | /** 127 | * fire select events 128 | */ 129 | select (event) { 130 | event.preventDefault(); 131 | event.stopPropagation(); 132 | // check if left mouse is clicked 133 | if (event.buttons !== 1) return; 134 | this.track.classList.add('is-dragging'); 135 | this.ticking = false; 136 | 137 | const stepValue = this.getStepValue(event); 138 | 139 | if (this.multiple) { 140 | let closest = getClosestValue(this.values, stepValue); 141 | this.activeHandle = this.values.indexOf(closest); 142 | } 143 | this.update(stepValue); 144 | 145 | this.tempDrag = this.dragging.bind(this); 146 | this.tempRelease = this.release.bind(this); 147 | document.addEventListener('mousemove', this.tempDrag); 148 | document.addEventListener('touchmove', this.tempDrag); 149 | document.addEventListener('touchend', this.tempRelease); 150 | document.addEventListener('mouseup', this.tempRelease); 151 | } 152 | 153 | /** 154 | * dragging motion 155 | */ 156 | dragging (event) { 157 | event.preventDefault(); 158 | const stepValue = this.getStepValue(event); 159 | if (!this.ticking) { 160 | window.requestAnimationFrame(() => { 161 | this.update(stepValue); 162 | this.ticking = false; 163 | }); 164 | 165 | this.ticking = true; 166 | } 167 | } 168 | 169 | /** 170 | * release handler 171 | */ 172 | release () { 173 | this.track.classList.remove('is-dragging'); 174 | document.removeEventListener('mousemove', this.tempDrag); 175 | document.removeEventListener('touchmove', this.tempDrag); 176 | document.removeEventListener('mouseup', this.tempRelease); 177 | document.removeEventListener('touchend', this.tempRelease); 178 | } 179 | 180 | getStepValue (event) { 181 | const eventX = event.type.includes('mouse') 182 | ? event.clientX : event.type.includes('touch') 183 | ? event.touches[0].clientX : event; 184 | 185 | const mouseValue = (eventX - this.currentX); 186 | const stepCount = parseInt((mouseValue / this.stepWidth) + 0.5, 10); 187 | const stepValue = parseInt((stepCount + this.min) / this.step, 10) * this.step; 188 | return stepValue; 189 | } 190 | 191 | updateWidth () { 192 | const trackRect = this.track.getBoundingClientRect(); 193 | this.currentX = trackRect.left; 194 | this.width = trackRect.width; 195 | this.stepWidth = (this.width / (this.max - this.min)); 196 | } 197 | 198 | /** 199 | * get the filled area percentage 200 | * @param {Object} slider 201 | * @param {Number} value 202 | * @return {Number} 203 | */ 204 | getPositionPercentage (value) { 205 | return (value - this.min) / (this.max - this.min); 206 | } 207 | 208 | normalizeValue (value) { 209 | if (isNaN(Number(value))) { 210 | return this.value; 211 | } 212 | if (this.multiple) { 213 | const prevValue = this.values[this.activeHandle - 1] || this.min; 214 | const nextValue = this.values[this.activeHandle + 1] || this.max; 215 | value = Math.min(Math.max(Number(value), prevValue), nextValue); 216 | } 217 | return Math.min(Math.max(Number(value), this.min), this.max); 218 | } 219 | 220 | newGradient (newGradient) { 221 | this.settings.gradient = newGradient; 222 | this._initGradient(); 223 | this.update(undefined, true); 224 | } 225 | 226 | addHandle (value) { 227 | const closest = getClosestValue(this.values, value); 228 | const closestIndex = this.values.indexOf(closest); 229 | const closestValue = this.values[closestIndex]; 230 | const newIndex = closestValue <= value ? closestIndex + 1 : closestIndex; 231 | this.values.splice(newIndex, 0, value); 232 | this.percentages.splice(newIndex, 0, this.getPositionPercentage(value)); 233 | this.handles.splice(newIndex, 0, stringToDOM(`
`)); 234 | if (this.settings.label) { 235 | this.labels.splice(newIndex, 0, stringToDOM(`
`)); 236 | this.handles[newIndex].appendChild(this.labels[newIndex]); 237 | } 238 | this.handles[newIndex].addEventListener('mousedown', this.select.bind(this), false); 239 | this.handles[newIndex].addEventListener('touchstart', this.select.bind(this), false); 240 | this.track.appendChild(this.handles[newIndex]); 241 | this.activeHandle = newIndex; 242 | this.value = null; 243 | this.update(value); 244 | return this.handles[newIndex]; 245 | } 246 | 247 | removeHandle (index) { 248 | this.handles[index].remove(); 249 | this.handles.splice(index, 1); 250 | this.values.splice(index, 1); 251 | this.percentages.splice(index, 1); 252 | if (this.settings.label) { 253 | this.labels.splice(index, 1); 254 | } 255 | this.activeHandle = index === 0 ? index + 1 : index - 1; 256 | } 257 | 258 | /** 259 | * get the handle color 260 | * @param {Number} positionPercentage 261 | * @return {Number} handle hex color code 262 | */ 263 | getHandleColor (positionPercentage) { 264 | const colorCount = this.gradient.length - 1; 265 | const region = positionPercentage; 266 | for (let i = 1; i <= colorCount; i++) { 267 | // check the current zone 268 | if (region >= ((i - 1) / colorCount) && region <= (i / colorCount)) { 269 | // get the active color percentage 270 | const colorPercentage = (region - ((i - 1) / colorCount)) / (1 / colorCount); 271 | // return the mixed color based on the zone boundary colors 272 | return mixColors(this.gradient[i - 1], this.gradient[i], colorPercentage); 273 | } 274 | } 275 | return 'rgb(0, 0, 0)'; 276 | } 277 | 278 | /** 279 | * update the slider fill, value and color 280 | * @param {Number} value 281 | */ 282 | update (value, mute = false) { 283 | if (Number(value) === this.value) return; 284 | 285 | if (!this.width) { 286 | this.updateWidth(); 287 | } 288 | const normalized = this.normalizeValue(value); 289 | const positionPercentage = this.getPositionPercentage(normalized); 290 | 291 | if (this.fill) { 292 | this.fill.style.transform = `translate(${positionPercentage * this.width}px, 0) scale(${1 - positionPercentage}, 1)`; 293 | } 294 | this.handles[this.activeHandle].style.transform = `translate(${positionPercentage * this.width}px, 0)`; 295 | this.value = normalized; 296 | this.values[this.activeHandle] = normalized; 297 | this.percentages[this.activeHandle] = positionPercentage; 298 | this.el.value = this.value; 299 | if (this.settings.label) { 300 | this.labels[this.activeHandle].innerHTML = this.value; 301 | } 302 | if (this.gradient) { 303 | const color = this.getHandleColor(positionPercentage); 304 | this.handles[this.activeHandle].style.color = color; 305 | if (this.settings.colorCode) { 306 | this.el.value = color; 307 | this.labels[this.activeHandle].innerHTML = color; 308 | } 309 | } 310 | if (mute) return; 311 | this.el.dispatchEvent(new Event('change')); // eslint-disable-line 312 | this.el.dispatchEvent(new Event('input')); // eslint-disable-line 313 | call(this.settings.updated); 314 | } 315 | 316 | // eslint-disable-next-line 317 | static defaults = { 318 | created: {}, 319 | updated: {}, 320 | gradient: null, 321 | classes: null, 322 | colorCode: false, 323 | editable: false, 324 | reverse: false, 325 | label: true, 326 | min: 0, 327 | max: 10, 328 | step: 1, 329 | value: 0, 330 | handles: [0], 331 | trackSlide: true 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /extensions/modal/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | blexar modal 8 | 9 | 10 | 11 |
12 |
13 |

Blexar Modal

14 |

A modal displays content that temporarily blocks interactions with the main view of a site

15 |
16 |
17 |
18 |

Default

19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 |

Outline

37 |
38 |
39 | 40 |
41 |
42 | 43 |
44 |
45 | 46 |
47 |
48 | 49 |
50 |
51 | 52 |
53 |
54 | 55 | 75 | 76 | 96 | 97 | 117 | 118 | 138 | 139 | 159 | 160 | 180 | 181 | 201 | 202 | 222 | 223 | 243 | 244 | 264 | 265 | 285 |
286 | 287 | 288 | 289 | 290 | 297 | 298 | --------------------------------------------------------------------------------