From bc39cd197cf4f6f868af097d5ee745c144b06199 Mon Sep 17 00:00:00 2001 From: Sahat Yalkabov Date: Wed, 18 Dec 2013 02:57:24 -0500 Subject: [PATCH] Flat UI checkboxes and radio buttons --- public/css/{themes => }/flatly.less | 387 +++++++++++++++++++++++++++- public/css/styles.less | 8 +- public/js/lib/flatui-checkbox.js | 112 ++++++++ public/js/lib/flatui-radio.js | 141 ++++++++++ views/layout.jade | 2 + 5 files changed, 638 insertions(+), 12 deletions(-) rename public/css/{themes => }/flatly.less (72%) create mode 100755 public/js/lib/flatui-checkbox.js create mode 100755 public/js/lib/flatui-radio.js diff --git a/public/css/themes/flatly.less b/public/css/flatly.less similarity index 72% rename from public/css/themes/flatly.less rename to public/css/flatly.less index 86b5358348..5dac9a6a32 100644 --- a/public/css/themes/flatly.less +++ b/public/css/flatly.less @@ -1,16 +1,240 @@ -// Flatly 3.0.3 +// Flatly 3.0.3 (MODIFIED) // Bootswatch // ----------------------------------------------------- -@import url(http://fonts.googleapis.com/css?family=Lato); -// Flatly 3.0.3 +// Fonts +// -------------------------------------------------- +@font-face { + font-family: 'Lato'; + src: url('../fonts/lato/lato-black-webfont.eot'); + src: url('../fonts/lato/lato-black-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato/lato-black-webfont.woff') format('woff'), + url('../fonts/lato/lato-black-webfont.ttf') format('truetype'), + url('../fonts/lato/lato-black-webfont.svg#latoblack') format('svg'); + font-weight: 900; + font-style: normal; +} + +@font-face { + font-family: 'Lato'; + src: url('../fonts/lato/lato-bold-webfont.eot'); + src: url('../fonts/lato/lato-bold-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato/lato-bold-webfont.woff') format('woff'), + url('../fonts/lato/lato-bold-webfont.ttf') format('truetype'), + url('../fonts/lato/lato-bold-webfont.svg#latobold') format('svg'); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: 'Lato'; + src: url('../fonts/lato/lato-bolditalic-webfont.eot'); + src: url('../fonts/lato/lato-bolditalic-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato/lato-bolditalic-webfont.woff') format('woff'), + url('../fonts/lato/lato-bolditalic-webfont.ttf') format('truetype'), + url('../fonts/lato/lato-bolditalic-webfont.svg#latobold_italic') format('svg'); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: 'Lato'; + src: url('../fonts/lato/lato-italic-webfont.eot'); + src: url('../fonts/lato/lato-italic-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato/lato-italic-webfont.woff') format('woff'), + url('../fonts/lato/lato-italic-webfont.ttf') format('truetype'), + url('../fonts/lato/lato-italic-webfont.svg#latoitalic') format('svg'); + font-weight: normal; + font-style: italic; +} + +@font-face { + font-family: 'Lato'; + src: url('../fonts/lato/lato-light-webfont.eot'); + src: url('../fonts/lato/lato-light-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato/lato-light-webfont.woff') format('woff'), + url('../fonts/lato/lato-light-webfont.ttf') format('truetype'), + url('../fonts/lato/lato-light-webfont.svg#latolight') format('svg'); + font-weight: 300; + font-style: normal; +} + +@font-face { + font-family: 'Lato'; + src: url('../fonts/lato/lato-regular-webfont.eot'); + src: url('../fonts/lato/lato-regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/lato/lato-regular-webfont.woff') format('woff'), + url('../fonts/lato/lato-regular-webfont.ttf') format('truetype'), + url('../fonts/lato/lato-regular-webfont.svg#latoregular') format('svg'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Flat-UI-Icons'; + src:url('../fonts/Flat-UI-Icons.eot'); + src:url('../fonts/Flat-UI-Icons.eot?#iefix') format('embedded-opentype'), + url('../fonts/Flat-UI-Icons.woff') format('woff'), + url('../fonts/Flat-UI-Icons.ttf') format('truetype'), + url('../fonts/Flat-UI-Icons.svg#Flat-UI-Icons') format('svg'); + font-weight: normal; + font-style: normal; +} + +/* Use the following CSS code if you want to use data attributes for inserting your icons */ +[data-icon]:before { + font-family: 'Flat-UI-Icons'; + content: attr(data-icon); + speak: none; + font-weight: normal; + font-variant: normal; + text-transform: none; + -webkit-font-smoothing: antialiased; +} + +/* Use the following CSS code if you want to have a class per icon */ +/* +Instead of a list of all class selectors, +you can use the generic selector below, but it's slower: +[class*="fui-"] { +*/ +.fui-arrow-right, .fui-arrow-left, .fui-cmd, .fui-check-inverted, .fui-heart, .fui-location, .fui-plus, .fui-check, .fui-cross, .fui-list, .fui-new, .fui-video, .fui-photo, .fui-volume, .fui-time, .fui-eye, .fui-chat, .fui-search, .fui-user, .fui-mail, .fui-lock, .fui-gear, .fui-radio-unchecked, .fui-radio-checked, .fui-checkbox-unchecked, .fui-checkbox-checked, .fui-calendar-solid, .fui-pause, .fui-play, .fui-check-inverted-2 { + display: inline-block; + font-family: 'Flat-UI-Icons'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + -webkit-font-smoothing: antialiased; +} +.fui-arrow-right:before { + content: "\e02c"; +} +.fui-arrow-left:before { + content: "\e02d"; +} +.fui-cmd:before { + content: "\e02f"; +} +.fui-check-inverted:before { + content: "\e006"; +} +.fui-heart:before { + content: "\e007"; +} +.fui-location:before { + content: "\e008"; +} +.fui-plus:before { + content: "\e009"; +} +.fui-check:before { + content: "\e00a"; +} +.fui-cross:before { + content: "\e00b"; +} +.fui-list:before { + content: "\e00c"; +} +.fui-new:before { + content: "\e00d"; +} +.fui-video:before { + content: "\e00e"; +} +.fui-photo:before { + content: "\e00f"; +} +.fui-volume:before { + content: "\e010"; +} +.fui-time:before { + content: "\e011"; +} +.fui-eye:before { + content: "\e012"; +} +.fui-chat:before { + content: "\e013"; +} +.fui-search:before { + content: "\e01c"; +} +.fui-user:before { + content: "\e01d"; +} +.fui-mail:before { + content: "\e01e"; +} +.fui-lock:before { + content: "\e01f"; +} +.fui-gear:before { + content: "\e024"; +} +.fui-radio-unchecked:before { + content: "\e02b"; +} +.fui-radio-checked:before { + content: "\e032"; +} +.fui-checkbox-unchecked:before { + content: "\e033"; +} +.fui-checkbox-checked:before { + content: "\e034"; +} +.fui-calendar-solid:before { + content: "\e022"; +} +.fui-pause:before { + content: "\e03b"; +} +.fui-play:before { + content: "\e03c"; +} +.fui-check-inverted-2:before { + content: "\e000"; +} + + // Variables // -------------------------------------------------- // Global values // -------------------------------------------------- +@turquoise: #1abc9c; +@green-sea: #16a085; +@emerald: #2ecc71; +@nephritis: #27ae60; + +@peter-river: #3498db; +@belize-hole: #2980b9; + +@amethyst: #9b59b6; +@wisteria: #8e44ad; + +@wet-asphalt: #34495e; +@midnight-blue: #2c3e50; + +@sun-flower: #f1c40f; +@orange: #f39c12; + +@carrot: #e67e22; +@pumpkin: #d35400; + +@alizarin: #e74c3c; +@pomegranate: #c0392b; + +@clouds: #ecf0f1; +@silver: #bdc3c7; + +@concrete: #95a5a6; +@asbestos: #7f8c8d; // Grays // ------------------------- @@ -647,18 +871,17 @@ @container-large-desktop: ((1140px + @grid-gutter-width)); @container-lg: @container-large-desktop; -@import url("//fonts.googleapis.com/css?family=Lato:400,700,900,400italic"); // Navbar ===================================================================== // Buttons ==================================================================== .btn:active { - .box-shadow(none); + box-shadow: none; } .btn-group.open .dropdown-toggle { - .box-shadow(none); + box-shadow: none; } // Typography ================================================================= @@ -718,10 +941,10 @@ input[type="tel"], input[type="color"], .uneditable-input { border-width: 2px; - .box-shadow(none); + box-shadow: none; &:focus { - .box-shadow(none); + box-shadow: none; } } @@ -819,12 +1042,156 @@ input[type="color"], .progress { height: 10px; - .box-shadow(none); + box-shadow: none; } // Containers ================================================================= .well { - .box-shadow(none); + box-shadow: none; border-width: 0; } + +// +// Checkbox & Radio +// -------------------------------------------------- + +.checkbox, +.radio { + margin-bottom: 12px; + padding-left: 32px; + position: relative; + transition: color .25s linear; + font-size: ceil(@font-size-base * 0.933); // ~14px + line-height: 1.5; // 21px; + + input { + outline: none !important; + display: none; + } + + // Replace icons + // -------------------------------------------------- + .icons { + color: @gray-light; + display: block; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; + text-align: center; + line-height: 21px; + font-size: 20px; + cursor: pointer; + transition: color .25s linear; + + .first-icon, + .second-icon { + display: inline-table; + position: absolute; + left: 0; + top: 0; + background-color: #fff; + margin: 0; + opacity: 1; + } + .second-icon { + opacity: 0; + } + } + + // Alternate States + // -------------------------------------------------- + + // Hover State + &:hover { + transition: color .25s linear; + + .first-icon { + opacity: 0; + } + .second-icon { + opacity: 1; + } + } + + // Checked State + &.checked { + color: @brand-success; + + .first-icon { + opacity: 0; + } + .second-icon { + opacity: 1; + color: @brand-success; + transition: color .25s linear; + } + } + + // Disabled state + &.disabled { + cursor: default; + color: mix(@gray-light, white, 38%); + + .icons { + color: mix(@gray-light, white, 38%); + } + .first-icon { + opacity: 1; + } + .second-icon { + opacity: 0; + } + &.checked { + .icons { + color: mix(@gray-light, white, 38%); + } + .first-icon { + opacity: 0; + } + .second-icon { + opacity: 1; + color: mix(@gray-light, white, 38%); + } + } + } + + // Alternate Color + // -------------------------------------------------- + + // Primary + &.primary { + .icons { + color: @brand-primary; + } + // Checked State + &.checked { + color: @brand-success; + + .icons { + color: @brand-success; + } + } + // Disabled state + &.disabled { + cursor: default; + color: @gray-light; + + .icons { + color: @gray-light; + } + &.checked { + .icons { + color: @gray-light; + } + } + } + } +} + +.radio + .radio, +.checkbox + .checkbox { + margin-top: 10px; +} \ No newline at end of file diff --git a/public/css/styles.less b/public/css/styles.less index e8c6ad1d55..a5a6c225d0 100644 --- a/public/css/styles.less +++ b/public/css/styles.less @@ -1,8 +1,8 @@ @import "bootstrap/bootstrap"; -@import "themes/flatly"; +@import "flatly"; body { - padding-top: 80px; + padding-top: 70px; } .navbar-nav img { @@ -37,6 +37,10 @@ body { border-color: #333; } +.form-horizontal .radio { + padding-top: 0; +} + // Search field .dataTables_filter { float: right; diff --git a/public/js/lib/flatui-checkbox.js b/public/js/lib/flatui-checkbox.js new file mode 100755 index 0000000000..93dca390f4 --- /dev/null +++ b/public/js/lib/flatui-checkbox.js @@ -0,0 +1,112 @@ +/* ============================================================= + * flatui-checkbox.js v0.0.3 + * ============================================================ */ + +!function ($) { + + /* CHECKBOX PUBLIC CLASS DEFINITION + * ============================== */ + + var Checkbox = function (element, options) { + this.init(element, options); + } + + Checkbox.prototype = { + + constructor: Checkbox + + , init: function (element, options) { + var $el = this.$element = $(element) + + this.options = $.extend({}, $.fn.checkbox.defaults, options); + $el.before(this.options.template); + this.setState(); + } + + , setState: function () { + var $el = this.$element + , $parent = $el.closest('.checkbox'); + + $el.prop('disabled') && $parent.addClass('disabled'); + $el.prop('checked') && $parent.addClass('checked'); + } + + , toggle: function () { + var ch = 'checked' + , $el = this.$element + , $parent = $el.closest('.checkbox') + , checked = $el.prop(ch) + , e = $.Event('toggle') + + if ($el.prop('disabled') == false) { + $parent.toggleClass(ch) && checked ? $el.removeAttr(ch) : $el.prop(ch, ch); + $el.trigger(e).trigger('change'); + } + } + + , setCheck: function (option) { + var d = 'disabled' + , ch = 'checked' + , $el = this.$element + , $parent = $el.closest('.checkbox') + , checkAction = option == 'check' ? true : false + , e = $.Event(option) + + $parent[checkAction ? 'addClass' : 'removeClass' ](ch) && checkAction ? $el.prop(ch, ch) : $el.removeAttr(ch); + $el.trigger(e).trigger('change'); + } + + } + + + /* CHECKBOX PLUGIN DEFINITION + * ======================== */ + + var old = $.fn.checkbox + + $.fn.checkbox = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('checkbox') + , options = $.extend({}, $.fn.checkbox.defaults, $this.data(), typeof option == 'object' && option); + if (!data) $this.data('checkbox', (data = new Checkbox(this, options))); + if (option == 'toggle') data.toggle() + if (option == 'check' || option == 'uncheck') data.setCheck(option) + else if (option) data.setState(); + }); + } + + $.fn.checkbox.defaults = { + template: '' + } + + + /* CHECKBOX NO CONFLICT + * ================== */ + + $.fn.checkbox.noConflict = function () { + $.fn.checkbox = old; + return this; + } + + + /* CHECKBOX DATA-API + * =============== */ + + $(document).on('click.checkbox.data-api', '[data-toggle^=checkbox], .checkbox', function (e) { + var $checkbox = $(e.target); + if (e.target.tagName != "A") { + e && e.preventDefault() && e.stopPropagation(); + if (!$checkbox.hasClass('checkbox')) $checkbox = $checkbox.closest('.checkbox'); + $checkbox.find(':checkbox').checkbox('toggle'); + } + }); + + $(function () { + $('[data-toggle="checkbox"]').each(function () { + var $checkbox = $(this); + $checkbox.checkbox(); + }); + }); + +}(window.jQuery); \ No newline at end of file diff --git a/public/js/lib/flatui-radio.js b/public/js/lib/flatui-radio.js new file mode 100755 index 0000000000..005c2e1ff3 --- /dev/null +++ b/public/js/lib/flatui-radio.js @@ -0,0 +1,141 @@ +/* ============================================================= + * flatui-radio.js v0.0.3 + * ============================================================ */ + +!function ($) { + + /* RADIO PUBLIC CLASS DEFINITION + * ============================== */ + + var Radio = function (element, options) { + this.init(element, options); + } + + Radio.prototype = { + + constructor: Radio + + , init: function (element, options) { + var $el = this.$element = $(element) + + this.options = $.extend({}, $.fn.radio.defaults, options); + $el.before(this.options.template); + this.setState(); + } + + , setState: function () { + var $el = this.$element + , $parent = $el.closest('.radio'); + + $el.prop('disabled') && $parent.addClass('disabled'); + $el.prop('checked') && $parent.addClass('checked'); + } + + , toggle: function () { + var d = 'disabled' + , ch = 'checked' + , $el = this.$element + , checked = $el.prop(ch) + , $parent = $el.closest('.radio') + , $parentWrap = $el.closest('form').length ? $el.closest('form') : $el.closest('body') + , $elemGroup = $parentWrap.find(':radio[name="' + $el.attr('name') + '"]') + , e = $.Event('toggle') + + $elemGroup.not($el).each(function () { + var $el = $(this) + , $parent = $(this).closest('.radio'); + + if ($el.prop(d) == false) { + $parent.removeClass(ch) && $el.removeAttr(ch).trigger('change'); + } + }); + + if ($el.prop(d) == false) { + if (checked == false) $parent.addClass(ch) && $el.attr(ch, true); + $el.trigger(e); + + if (checked !== $el.prop(ch)) { + $el.trigger('change'); + } + } + } + + , setCheck: function (option) { + var ch = 'checked' + , $el = this.$element + , $parent = $el.closest('.radio') + , checkAction = option == 'check' ? true : false + , checked = $el.prop(ch) + , $parentWrap = $el.closest('form').length ? $el.closest('form') : $el.closest('body') + , $elemGroup = $parentWrap.find(':radio[name="' + $el['attr']('name') + '"]') + , e = $.Event(option) + + $elemGroup.not($el).each(function () { + var $el = $(this) + , $parent = $(this).closest('.radio'); + + $parent.removeClass(ch) && $el.removeAttr(ch); + }); + + $parent[checkAction ? 'addClass' : 'removeClass'](ch) && checkAction ? $el.prop(ch, ch) : $el.removeAttr(ch); + $el.trigger(e); + + if (checked !== $el.prop(ch)) { + $el.trigger('change'); + } + } + + } + + + /* RADIO PLUGIN DEFINITION + * ======================== */ + + var old = $.fn.radio + + $.fn.radio = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('radio') + , options = $.extend({}, $.fn.radio.defaults, $this.data(), typeof option == 'object' && option); + if (!data) $this.data('radio', (data = new Radio(this, options))); + if (option == 'toggle') data.toggle() + if (option == 'check' || option == 'uncheck') data.setCheck(option) + else if (option) data.setState(); + }); + } + + $.fn.radio.defaults = { + template: '' + } + + + /* RADIO NO CONFLICT + * ================== */ + + $.fn.radio.noConflict = function () { + $.fn.radio = old; + return this; + } + + + /* RADIO DATA-API + * =============== */ + + $(document).on('click.radio.data-api', '[data-toggle^=radio], .radio', function (e) { + var $radio = $(e.target); + if (e.target.tagName != "A") { + e && e.preventDefault() && e.stopPropagation(); + if (!$radio.hasClass('radio')) $radio = $radio.closest('.radio'); + $radio.find(':radio').radio('toggle'); + } + }); + + $(function () { + $('[data-toggle="radio"]').each(function () { + var $radio = $(this); + $radio.radio(); + }); + }); + +}(window.jQuery); \ No newline at end of file diff --git a/views/layout.jade b/views/layout.jade index ccf0066553..97e80639b4 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -14,6 +14,8 @@ html script(src='/js/lib/jquery.js') script(src='/js/lib/jquery.dataTables.min.js') script(src='/js/lib/bootstrap.js') + script(src='/js/lib/flatui-checkbox.js') + script(src='/js/lib/flatui-radio.js') script(src='/js/main.js') body .navbar.navbar-default.navbar-fixed-top