diff options
Diffstat (limited to 'src')
72 files changed, 5583 insertions, 0 deletions
diff --git a/src/images/cover-v1.2.0.jpg b/src/images/cover-v1.2.0.jpg Binary files differnew file mode 100755 index 0000000..2d5a0e1 --- /dev/null +++ b/src/images/cover-v1.2.0.jpg diff --git a/src/images/cover.jpg b/src/images/cover.jpg Binary files differnew file mode 100755 index 0000000..8956839 --- /dev/null +++ b/src/images/cover.jpg diff --git a/src/js/.eslintrc.json b/src/js/.eslintrc.json new file mode 100644 index 0000000..c7db13a --- /dev/null +++ b/src/js/.eslintrc.json @@ -0,0 +1,10 @@ +{ + "globals": { + "jQuery": false, + "moment": false, + "algoliaIndex": false + }, + "env": { + "browser": true + } +}
\ No newline at end of file diff --git a/src/js/about.js b/src/js/about.js new file mode 100755 index 0000000..ba7c8ae --- /dev/null +++ b/src/js/about.js @@ -0,0 +1,123 @@ +(function($) { + 'use strict'; + + // Fade out the blog and let drop the about card of the author and vice versa + + /** + * AboutCard + * @constructor + */ + var AboutCard = function() { + this.$openBtn = $("#sidebar, #header").find("a[href*='#about']"); + this.$closeBtn = $('#about-btn-close'); + this.$blog = $('#blog'); + this.$about = $('#about'); + this.$aboutCard = $('#about-card'); + }; + + AboutCard.prototype = { + + /** + * Run AboutCard feature + * @return {void} + */ + run: function() { + var self = this; + // Detect click on open button + self.$openBtn.click(function(e) { + e.preventDefault(); + self.play(); + }); + // Detect click on close button + self.$closeBtn.click(function(e) { + e.preventDefault(); + self.playBack(); + }); + }, + + /** + * Play the animation + * @return {void} + */ + play: function() { + var self = this; + // Fade out the blog + self.$blog.fadeOut(); + // Fade in the about card + self.$about.fadeIn(); + // Small timeout to drop the about card after that + // the about card fade in and the blog fade out + setTimeout(function() { + self.dropAboutCard(); + }, 300); + }, + + /** + * Play back the animation + * @return {void} + */ + playBack: function() { + var self = this; + // Lift the about card + self.liftAboutCard(); + // Fade in the blog after that the about card lifted up + setTimeout(function() { + self.$blog.fadeIn(); + }, 500); + // Fade out the about card after that the about card lifted up + setTimeout(function() { + self.$about.fadeOut(); + }, 500); + }, + + /** + * Slide the card to the middle + * @return {void} + */ + dropAboutCard: function() { + var self = this; + var aboutCardHeight = self.$aboutCard.innerHeight(); + // default offset from top + var offsetTop = ($(window).height() / 2) - (aboutCardHeight / 2) + aboutCardHeight; + // if card is longer than the window + // scroll is enable + // and re-define offsetTop + if (aboutCardHeight + 30 > $(window).height()) { + offsetTop = aboutCardHeight; + } + self.$aboutCard + .css('top', '0px') + .css('top', '-' + aboutCardHeight + 'px') + .show(500, function() { + self.$aboutCard.animate({ + top: '+=' + offsetTop + 'px' + }); + }); + }, + + /** + * Slide the card to the top + * @return {void} + */ + liftAboutCard: function() { + var self = this; + var aboutCardHeight = self.$aboutCard.innerHeight(); + // default offset from top + var offsetTop = ($(window).height() / 2) - (aboutCardHeight / 2) + aboutCardHeight; + if (aboutCardHeight + 30 > $(window).height()) { + offsetTop = aboutCardHeight; + } + self.$aboutCard.animate({ + top: '-=' + offsetTop + 'px' + }, 500, function() { + self.$aboutCard.hide(); + self.$aboutCard.removeAttr('style'); + }); + } + }; + + $(document).ready(function() { + var aboutCard = new AboutCard(); + aboutCard.run(); + }); +})(jQuery); diff --git a/src/js/archives-filter.js b/src/js/archives-filter.js new file mode 100755 index 0000000..49a0d29 --- /dev/null +++ b/src/js/archives-filter.js @@ -0,0 +1,160 @@ +(function($) { + 'use strict'; + + // Filter posts by using their date on archives page : `/archives` + + /** + * ArchivesFilter + * @param {String} archivesElem + * @constructor + */ + var ArchivesFilter = function(archivesElem) { + this.$form = $(archivesElem).find('#filter-form'); + this.$searchInput = $(archivesElem).find('input[name=date]'); + this.$archiveResult = $(archivesElem).find('.archive-result'); + this.$postsYear = $(archivesElem).find('.archive-year'); + this.$postsMonth = $(archivesElem).find('.archive-month'); + this.$postsDay = $(archivesElem).find('.archive-day'); + this.postsYear = archivesElem + ' .archive-year'; + this.postsMonth = archivesElem + ' .archive-month'; + this.postsDay = archivesElem + ' .archive-day'; + this.messages = { + zero: this.$archiveResult.data('message-zero'), + one: this.$archiveResult.data('message-one'), + other: this.$archiveResult.data('message-other') + }; + }; + + ArchivesFilter.prototype = { + + /** + * Run ArchivesFilter feature + * @return {void} + */ + run: function() { + var self = this; + + self.$searchInput.keyup(function() { + self.filter(self.sliceDate(self.getSearch())); + }); + + // Block submit action + self.$form.submit(function(e) { + e.preventDefault(); + }); + }, + + /** + * Get Filter entered by user + * @returns {String} The date entered by the user + */ + getSearch: function() { + return this.$searchInput.val().replace(/([\/|.|-])/g, '').toLowerCase(); + }, + + /** + * Slice the date by year, month and day + * @param {String} date - The date of the post + * @returns {Array} The date of the post splitted in a list + */ + sliceDate: function(date) { + return [ + date.slice(0, 4), + date.slice(4, 6), + date.slice(6) + ]; + }, + + /** + * Show related posts and hide others + * @param {String} date - The date of the post + * @returns {void} + */ + filter: function(date) { + var numberPosts; + + // Check if the search is empty + if (date[0] === '') { + this.showAll(); + this.showResult(-1); + } + else { + numberPosts = this.countPosts(date); + + this.hideAll(); + this.showResult(numberPosts); + + if (numberPosts > 0) { + this.showPosts(date); + } + } + }, + + /** + * Display results + * @param {Number} numbPosts - The number of posts found + * @returns {void} + */ + showResult: function(numbPosts) { + if (numbPosts === -1) { + this.$archiveResult.html('').hide(); + } + else if (numbPosts === 0) { + this.$archiveResult.html(this.messages.zero).show(); + } + else if (numbPosts === 1) { + this.$archiveResult.html(this.messages.one).show(); + } + else { + this.$archiveResult.html(this.messages.other.replace(/\{n\}/, numbPosts)).show(); + } + }, + + /** + * Count number of posts + * @param {String} date - The date of the post + * @returns {Number} The number of posts found + */ + countPosts: function(date) { + return $(this.postsDay + '[data-date^=' + date[0] + date[1] + date[2] + ']').length; + }, + + /** + * Show all posts from a date + * @param {String} date - The date of the post + * @returns {void} + */ + showPosts: function(date) { + $(this.postsYear + '[data-date^=' + date[0] + ']').show(); + $(this.postsMonth + '[data-date^=' + date[0] + date[1] + ']').show(); + $(this.postsDay + '[data-date^=' + date[0] + date[1] + date[2] + ']').show(); + }, + + /** + * Show all posts + * @returns {void} + */ + showAll: function() { + this.$postsYear.show(); + this.$postsMonth.show(); + this.$postsDay.show(); + }, + + /** + * Hide all posts + * @returns {void} + */ + hideAll: function() { + this.$postsYear.hide(); + this.$postsMonth.hide(); + this.$postsDay.hide(); + } + }; + + $(document).ready(function() { + if ($('#archives').length) { + var archivesFilter = new ArchivesFilter('#archives'); + archivesFilter.run(); + } + }); +})(jQuery); diff --git a/src/js/categories-filter.js b/src/js/categories-filter.js new file mode 100755 index 0000000..d3c8a53 --- /dev/null +++ b/src/js/categories-filter.js @@ -0,0 +1,166 @@ +(function($) { + 'use strict'; + + // Filter posts by using their categories on categories page : `/categories` + + /** + * CategoriesFilter + * @param {String} categoriesArchivesElem + * @constructor + */ + var CategoriesFilter = function(categoriesArchivesElem) { + this.$form = $(categoriesArchivesElem).find('#filter-form'); + this.$inputSearch = $(categoriesArchivesElem).find('input[name=category]'); + // Element where result of the filter are displayed + this.$archiveResult = $(categoriesArchivesElem).find('.archive-result'); + this.$posts = $(categoriesArchivesElem).find('.archive'); + this.$categories = $(categoriesArchivesElem).find('.category-anchor'); + this.posts = categoriesArchivesElem + ' .archive'; + this.categories = categoriesArchivesElem + ' .category-anchor'; + // Html data attribute without `data-` of `.archive` element + // which contains the name of category + this.dataCategory = 'category'; + // Html data attribute without `data-` of `.archive` element + // which contains the name of parent's categories + this.dataParentCategories = 'parent-categories'; + this.messages = { + zero: this.$archiveResult.data('message-zero'), + one: this.$archiveResult.data('message-one'), + other: this.$archiveResult.data('message-other') + }; + }; + + CategoriesFilter.prototype = { + + /** + * Run CategoriesFilter feature + * @return {void} + */ + run: function() { + var self = this; + + self.$inputSearch.keyup(function() { + self.filter(self.getSearch()); + }); + + // Block submit action + self.$form.submit(function(e) { + e.preventDefault(); + }); + }, + + /** + * Get the search entered by user + * @returns {String} The name of the category + */ + getSearch: function() { + return this.$inputSearch.val().toLowerCase(); + }, + + /** + * Show related posts form a category and hide the others + * @param {string} category - The name of the category + * @return {void} + */ + filter: function(category) { + if (category === '') { + this.showAll(); + this.showResult(-1); + } + else { + this.hideAll(); + this.showPosts(category); + this.showResult(this.countCategories(category)); + } + }, + + /** + * Display results of the search + * @param {Number} numbCategories - The number of categories found + * @return {void} + */ + showResult: function(numbCategories) { + if (numbCategories === -1) { + this.$archiveResult.html('').hide(); + } + else if (numbCategories === 0) { + this.$archiveResult.html(this.messages.zero).show(); + } + else if (numbCategories === 1) { + this.$archiveResult.html(this.messages.one).show(); + } + else { + this.$archiveResult.html(this.messages.other.replace(/\{n\}/, numbCategories)).show(); + } + }, + + /** + * Count number of categories + * @param {String} category - The name of theThe date of the post category + * @returns {Number} The number of categories found + */ + countCategories: function(category) { + return $(this.posts + '[data-' + this.dataCategory + '*=\'' + category + '\']').length; + }, + + /** + * Show all posts from a category + * @param {String} category - The name of the category + * @return {void} + */ + showPosts: function(category) { + var self = this; + var parents; + var categories = self.categories + '[data-' + self.dataCategory + '*=\'' + category + '\']'; + var posts = self.posts + '[data-' + self.dataCategory + '*=\'' + category + '\']'; + + if (self.countCategories(category) > 0) { + // Check if selected categories have parents + if ($(categories + '[data-' + self.dataParentCategories + ']').length) { + // Get all categories that matches search + $(categories).each(function() { + // Get all its parents categories name + parents = $(this).attr('data-' + self.dataParentCategories).split(','); + // Show only the title of the parents's categories and hide their posts + parents.forEach(function(parent) { + var dataAttr = '[data-' + self.dataCategory + '=\'' + parent + '\']'; + $(self.categories + dataAttr).show(); + $(self.posts + dataAttr).show(); + $(self.posts + dataAttr + ' > .archive-posts > .archive-post').hide(); + }); + }); + } + } + // Show categories and related posts found + $(categories).show(); + $(posts).show(); + $(posts + ' > .archive-posts > .archive-post').show(); + }, + + /** + * Show all categories and all posts + * @return {void} + */ + showAll: function() { + this.$categories.show(); + this.$posts.show(); + $(this.posts + ' > .archive-posts > .archive-post').show(); + }, + + /** + * Hide all categories and all posts + * @return {void} + */ + hideAll: function() { + this.$categories.hide(); + this.$posts.hide(); + } + }; + + $(document).ready(function() { + if ($('#categories-archives').length) { + var categoriesFilter = new CategoriesFilter('#categories-archives'); + categoriesFilter.run(); + } + }); +})(jQuery); diff --git a/src/js/codeblock-resizer.js b/src/js/codeblock-resizer.js new file mode 100755 index 0000000..0228cc2 --- /dev/null +++ b/src/js/codeblock-resizer.js @@ -0,0 +1,58 @@ +(function($) { + 'use strict'; + + // Resize code blocks to fit the screen width + + /** + * Code block resizer + * @param {String} elem + * @constructor + */ + var CodeBlockResizer = function(elem) { + this.$codeBlocks = $(elem); + }; + + CodeBlockResizer.prototype = { + /** + * Run main feature + * @return {void} + */ + run: function() { + var self = this; + // resize all codeblocks + self.resize(); + // resize codeblocks when window is resized + $(window).smartresize(function() { + self.resize(); + }); + }, + + /** + * Resize codeblocks + * @return {void} + */ + resize: function() { + var self = this; + self.$codeBlocks.each(function() { + var $gutter = $(this).find('.gutter'); + var $code = $(this).find('.code'); + // get padding of code div + var codePaddings = $code.width() - $code.innerWidth(); + // code block div width with padding - gutter div with padding + code div padding + var width = $(this).outerWidth() - $gutter.outerWidth() + codePaddings; + // apply new width + $code.css('width', width); + $code.children('pre').css('width', width); + }); + } + }; + + $(document).ready(function() { + // register jQuery function to check if an element has an horizontal scroll bar + $.fn.hasHorizontalScrollBar = function() { + return this.get(0).scrollWidth > this.innerWidth(); + }; + var resizer = new CodeBlockResizer('figure.highlight'); + resizer.run(); + }); +})(jQuery); diff --git a/src/js/fancybox.js b/src/js/fancybox.js new file mode 100755 index 0000000..e06e4df --- /dev/null +++ b/src/js/fancybox.js @@ -0,0 +1,61 @@ +(function($) { + 'use strict'; + + // Run fancybox feature + + $(document).ready(function() { + /** + * Configure and run Fancybox plugin + * @returns {void} + */ + function fancyFox() { + var arrows = true; + var thumbs = null; + + // disable navigation arrows and display thumbs on medium and large screens + if ($(window).height() > 480) { + arrows = false; + thumbs = { + width: 70, + height: 70 + }; + } + + $('.fancybox').fancybox({ + maxWidth: 900, + maxHeight: 800, + fitToView: true, + width: '50%', + height: '50%', + autoSize: true, + arrows: arrows, + closeClick: false, + openEffect: 'elastic', + closeEffect: 'elastic', + prevEffect: 'none', + nextEffect: 'none', + padding: '0', + helpers: { + thumbs: thumbs, + overlay: { + css: { + overflow: 'hidden', + background: 'rgba(0, 0, 0, 0.85)' + } + } + }, + afterLoad: function() { + setTimeout(function() { + $('.fancybox-next > span, .fancybox-prev > span').css('visibility', 'visible'); + }, 400); + } + }); + } + + fancyFox(); + + $(window).smartresize(function() { + fancyFox(); + }); + }); +})(jQuery); diff --git a/src/js/header.js b/src/js/header.js new file mode 100755 index 0000000..3b499cc --- /dev/null +++ b/src/js/header.js @@ -0,0 +1,71 @@ +(function($) { + 'use strict'; + + // Hide the header when the user scrolls down, and show it when he scrolls up + + /** + * Header + * @constructor + */ + var Header = function() { + this.$header = $('#header'); + this.headerHeight = this.$header.height(); + // CSS class located in `source/_css/layout/_header.scss` + this.headerUpCSSClass = 'header-up'; + this.delta = 5; + this.lastScrollTop = 0; + }; + + Header.prototype = { + + /** + * Run Header feature + * @return {void} + */ + run: function() { + var self = this; + var didScroll; + + // Detect if the user is scrolling + $(window).scroll(function() { + didScroll = true; + }); + + // Check if the user scrolled every 250 milliseconds + setInterval(function() { + if (didScroll) { + self.animate(); + didScroll = false; + } + }, 250); + }, + + /** + * Animate the header + * @return {void} + */ + animate: function() { + var scrollTop = $(window).scrollTop(); + + // Check if the user scrolled more than `delta` + if (Math.abs(this.lastScrollTop - scrollTop) <= this.delta) { + return; + } + + // Checks if the user has scrolled enough down and has past the navbar + if ((scrollTop > this.lastScrollTop) && (scrollTop > this.headerHeight)) { + this.$header.addClass(this.headerUpCSSClass); + } + else if (scrollTop + $(window).height() < $(document).height()) { + this.$header.removeClass(this.headerUpCSSClass); + } + + this.lastScrollTop = scrollTop; + } + }; + + $(document).ready(function() { + var header = new Header(); + header.run(); + }); +})(jQuery); diff --git a/src/js/image-gallery.js b/src/js/image-gallery.js new file mode 100755 index 0000000..39c377d --- /dev/null +++ b/src/js/image-gallery.js @@ -0,0 +1,105 @@ +(function($) { + 'use strict'; + + // Resize all images of an image-gallery + + /** + * ImageGallery + * @constructor + */ + var ImageGallery = function() { + // CSS class located in `source/_css/components/_image-gallery.scss` + this.photosBox = '.photo-box'; + this.$images = $(this.photosBox + ' img'); + }; + ImageGallery.prototype = { + + /** + * Run ImageGallery feature + * @return {void} + */ + run: function() { + var self = this; + + // Resize all images at the loading of the page + self.resizeImages(); + + // Resize all images when the user is resizing the page + $(window).smartresize(function() { + self.resizeImages(); + }); + }, + + /** + * Resize all images of an image gallery + * @return {void} + */ + resizeImages: function() { + var photoBoxWidth; + var photoBoxHeight; + var imageWidth; + var imageHeight; + var imageRatio; + var $image; + + this.$images.each(function() { + $image = $(this); + photoBoxWidth = $image.parent().parent().width(); + photoBoxHeight = $image.parent().parent().innerHeight(); + imageWidth = $image.width(); + imageHeight = $image.height(); + + // Checks if image height is smaller than his box + if (imageHeight < photoBoxHeight) { + imageRatio = (imageWidth / imageHeight); + // Resize image with the box height + $image.css({ + height: photoBoxHeight, + width: (photoBoxHeight * imageRatio) + }); + // Center image in his box + $image.parent().css({ + left: '-' + (((photoBoxHeight * imageRatio) / 2) - (photoBoxWidth / 2)) + 'px' + }); + } + + // Update new values of height and width + imageWidth = $image.width(); + imageHeight = $image.height(); + + // Checks if image width is smaller than his box + if (imageWidth < photoBoxWidth) { + imageRatio = (imageHeight / imageWidth); + + $image.css({ + width: photoBoxWidth, + height: (photoBoxWidth * imageRatio) + }); + // Center image in his box + $image.parent().css({ + top: '-' + (((imageHeight) / 2) - (photoBoxHeight / 2)) + 'px' + }); + } + + // Checks if image height is larger than his box + if (imageHeight > photoBoxHeight) { + // Center image in his box + $image.parent().css({ + top: '-' + (((imageHeight) / 2) - (photoBoxHeight / 2)) + 'px' + }); + } + }); + } + }; + + $(document).ready(function() { + if ($('.image-gallery').length) { + var imageGallery = new ImageGallery(); + + // Small timeout to wait the loading of all images. + setTimeout(function() { + imageGallery.run(); + }, 500); + } + }); +})(jQuery); diff --git a/src/js/post-bottom-bar.js b/src/js/post-bottom-bar.js new file mode 100755 index 0000000..20fd5e9 --- /dev/null +++ b/src/js/post-bottom-bar.js @@ -0,0 +1,71 @@ +(function($) { + 'use strict'; + + // Hide the post bottom bar when the post footer is visible by the user, + // and show it when the post footer isn't visible by the user + + /** + * PostBottomBar + * @constructor + */ + var PostBottomBar = function() { + this.$postBottomBar = $('.post-bottom-bar'); + this.$postFooter = $('.post-actions-wrap'); + this.$header = $('#header'); + this.delta = 1; + this.lastScrollTop = 0; + }; + + PostBottomBar.prototype = { + + /** + * Run PostBottomBar feature + * @return {void} + */ + run: function() { + var self = this; + var didScroll; + // Run animation for first time + self.swipePostBottomBar(); + // Detects if the user is scrolling + $(window).scroll(function() { + didScroll = true; + }); + // Check if the user scrolled every 250 milliseconds + setInterval(function() { + if (didScroll) { + self.swipePostBottomBar(); + didScroll = false; + } + }, 250); + }, + + /** + * Swipe the post bottom bar + * @return {void} + */ + swipePostBottomBar: function() { + var scrollTop = $(window).scrollTop(); + var postFooterOffsetTop = this.$postFooter.offset().top; + // show bottom bar + // if the user scrolled upwards more than `delta` + // and `post-footer` div isn't visible + if (this.lastScrollTop > scrollTop && + (postFooterOffsetTop + this.$postFooter.height() > scrollTop + $(window).height() || + postFooterOffsetTop < scrollTop + this.$header.height())) { + this.$postBottomBar.slideDown(); + } + else { + this.$postBottomBar.slideUp(); + } + this.lastScrollTop = scrollTop; + } + }; + + $(document).ready(function() { + if ($('.post-bottom-bar').length) { + var postBottomBar = new PostBottomBar(); + postBottomBar.run(); + } + }); +})(jQuery); diff --git a/src/js/search-modal.js b/src/js/search-modal.js new file mode 100755 index 0000000..cfd1e50 --- /dev/null +++ b/src/js/search-modal.js @@ -0,0 +1,213 @@ +(function($) { + 'use strict'; + + /** + * Search modal with Algolia + * @constructor + */ + var SearchModal = function() { + this.$openButton = $('.open-algolia-search'); + this.$searchModal = $('#algolia-search-modal'); + this.$closeButton = this.$searchModal.find('.close-button'); + this.$searchForm = $('#algolia-search-form'); + this.$searchInput = $('#algolia-search-input'); + this.$results = this.$searchModal.find('.results'); + this.$noResults = this.$searchModal.find('.no-result'); + this.$resultsCount = this.$searchModal.find('.results-count'); + this.algolia = algoliaIndex; + }; + + SearchModal.prototype = { + /** + * Run feature + * @returns {void} + */ + run: function() { + var self = this; + + // open modal when open button is clicked + self.$openButton.click(function() { + self.open(); + }); + + // open modal when `s` button is pressed + $(document).keyup(function(event) { + var target = event.target || event.srcElement; + // exit if user is focusing an input + if (target.tagName.toUpperCase() === 'INPUT') { + return; + } + + if (event.keyCode === 83 && !self.$searchModal.is(':visible')) { + self.open(); + } + }); + + // close button when overlay is clicked + self.$searchModal.click(function(e) { + if (e.target === this) { + self.close(); + } + }); + + // close modal when close button is clicked + self.$closeButton.click(function() { + self.close(); + }); + + // close modal when `ESC` button is pressed + $(document).keyup(function(e) { + if (e.keyCode === 27 && self.$searchModal.is(':visible')) { + self.close(); + } + }); + + // send search when form is submitted + self.$searchForm.submit(function(event) { + event.preventDefault(); + self.search(self.$searchInput.val()); + }); + }, + + /** + * Open search modal and display overlay + * @returns {void} + */ + open: function() { + this.showSearchModal(); + this.showOverlay(); + this.$searchInput.focus(); + }, + + /** + * Close search modal and overlay + * @returns {void} + */ + close: function() { + this.hideSearchModal(); + this.hideOverlay(); + this.$searchInput.blur(); + }, + + /** + * Search with Algolia API and display results + * @param {String} search + * @returns {void} + */ + search: function(search) { + var self = this; + this.algolia.search(search, function(err, content) { + if (!err) { + self.showResults(content.hits); + self.showResultsCount(content.nbHits); + } + }); + }, + + /** + * Display results + * @param {Array} posts + * @returns {void} + */ + showResults: function(posts) { + var html = ''; + posts.forEach(function(post) { + var lang = window.navigator.userLanguage || window.navigator.language || post.lang; + + html += '<div class="media">'; + if (post.thumbnailImageUrl) { + html += '<div class="media-left">'; + html += '<a class="link-unstyled" href="' + (post.link || post.permalink) + '">'; + html += '<img class="media-image" ' + + 'src="' + post.thumbnailImageUrl + '" ' + + 'width="90" height="90"/>'; + html += '</a>'; + html += '</div>'; + } + + html += '<div class="media-body">'; + html += '<a class="link-unstyled" href="' + (post.link || post.permalink) + '">'; + html += '<h3 class="media-heading">' + post.title + '</h3>'; + html += '</a>'; + html += '<span class="media-meta">'; + html += '<span class="media-date text-small">'; + html += moment(post.date).locale(lang).format('ll'); + html += '</span>'; + html += '</span>'; + html += '<div class="media-content hide-xs font-merryweather">' + post.excerpt + '</div>'; + html += '</div>'; + html += '<div style="clear:both;"></div>'; + html += '<hr>'; + html += '</div>'; + }); + this.$results.html(html); + }, + + /** + * Show search modal + * @returns {void} + */ + showSearchModal: function() { + this.$searchModal.fadeIn(); + }, + + /** + * Hide search modal + * @returns {void} + */ + hideSearchModal: function() { + this.$searchModal.fadeOut(); + }, + + /** + * Display messages and counts of results + * @param {Number} count + * @returns {void} + */ + showResultsCount: function(count) { + var string = ''; + if (count < 1) { + string = this.$resultsCount.data('message-zero'); + this.$noResults.show(); + } + else if (count === 1) { + string = this.$resultsCount.data('message-one'); + this.$noResults.hide(); + } + else if (count > 1) { + string = this.$resultsCount.data('message-other').replace(/\{n\}/, count); + this.$noResults.hide(); + } + this.$resultsCount.html(string); + }, + + /** + * Show overlay + * @returns {void} + */ + showOverlay: function() { + $('body').append('<div class="overlay"></div>'); + $('.overlay').fadeIn(); + $('body').css('overflow', 'hidden'); + }, + + /** + * Hide overlay + * @returns {void} + */ + hideOverlay: function() { + $('.overlay').fadeOut(function() { + $(this).remove(); + $('body').css('overflow', 'auto'); + }); + } + }; + + $(document).ready(function() { + // launch feature only if there is an Algolia index available + if (typeof algoliaIndex !== 'undefined') { + var searchModal = new SearchModal(); + searchModal.run(); + } + }); +})(jQuery); diff --git a/src/js/share-options.js b/src/js/share-options.js new file mode 100755 index 0000000..5ea077b --- /dev/null +++ b/src/js/share-options.js @@ -0,0 +1,89 @@ +(function($) { + 'use strict'; + + // Open and close the share options bar + + /** + * ShareOptionsBar + * @constructor + */ + var ShareOptionsBar = function() { + this.$shareOptionsBar = $('#share-options-bar'); + this.$openBtn = $('.btn-open-shareoptions'); + this.$closeBtn = $('#share-options-mask'); + }; + + ShareOptionsBar.prototype = { + + /** + * Run ShareOptionsBar feature + * @return {void} + */ + run: function() { + var self = this; + + // Detect the click on the open button + self.$openBtn.click(function() { + if (!self.$shareOptionsBar.hasClass('opened')) { + self.openShareOptions(); + self.$closeBtn.show(); + } + }); + + // Detect the click on the close button + self.$closeBtn.click(function() { + if (self.$shareOptionsBar.hasClass('opened')) { + self.closeShareOptions(); + self.$closeBtn.hide(); + } + }); + }, + + /** + * Open share options bar + * @return {void} + */ + openShareOptions: function() { + var self = this; + + // Check if the share option bar isn't opened + // and prevent multiple click on the open button with `.processing` class + if (!self.$shareOptionsBar.hasClass('opened') && + !this.$shareOptionsBar.hasClass('processing')) { + // Open the share option bar + self.$shareOptionsBar.addClass('processing opened'); + + setTimeout(function() { + self.$shareOptionsBar.removeClass('processing'); + }, 250); + } + }, + + /** + * Close share options bar + * @return {void} + */ + closeShareOptions: function() { + var self = this; + + // Check if the share options bar is opened + // and prevent multiple click on the close button with `.processing` class + if (self.$shareOptionsBar.hasClass('opened') && + !this.$shareOptionsBar.hasClass('processing')) { + // Close the share option bar + self.$shareOptionsBar + .addClass('processing') + .removeClass('opened'); + + setTimeout(function() { + self.$shareOptionsBar.removeClass('processing'); + }, 250); + } + } + }; + + $(document).ready(function() { + var shareOptionsBar = new ShareOptionsBar(); + shareOptionsBar.run(); + }); +})(jQuery); diff --git a/src/js/sidebar.js b/src/js/sidebar.js new file mode 100755 index 0000000..7016678 --- /dev/null +++ b/src/js/sidebar.js @@ -0,0 +1,167 @@ +(function($) { + 'use strict'; + + // Open and close the sidebar by swiping the sidebar and the blog and vice versa + + /** + * Sidebar + * @constructor + */ + var Sidebar = function() { + this.$sidebar = $('#sidebar'); + this.$openBtn = $('#btn-open-sidebar'); + // Elements where the user can click to close the sidebar + this.$closeBtn = $('#header, #main, .post-header-cover'); + // Elements affected by the swipe of the sidebar + // The `pushed` class is added to each elements + // Each element has a different behavior when the sidebar is opened + this.$blog = $('.post-bottom-bar, #header, #main, .post-header-cover'); + // If you change value of `mediumScreenWidth`, + // you have to change value of `$screen-min: (md-min)` too + // in `source/_css/utils/variables.scss` + this.$body = $('body'); + this.mediumScreenWidth = 768; + }; + + Sidebar.prototype = { + /** + * Run Sidebar feature + * @return {void} + */ + run: function() { + var self = this; + // Detect the click on the open button + this.$openBtn.click(function() { + if (!self.$sidebar.hasClass('pushed')) { + self.openSidebar(); + } + }); + // Detect the click on close button + this.$closeBtn.click(function() { + if (self.$sidebar.hasClass('pushed')) { + self.closeSidebar(); + } + }); + // Detect resize of the windows + $(window).resize(function() { + // Check if the window is larger than the minimal medium screen value + if ($(window).width() > self.mediumScreenWidth) { + self.resetSidebarPosition(); + self.resetBlogPosition(); + } + else { + self.closeSidebar(); + } + }); + }, + + /** + * Open the sidebar by swiping to the right the sidebar and the blog + * @return {void} + */ + openSidebar: function() { + this.swipeBlogToRight(); + this.swipeSidebarToRight(); + }, + + /** + * Close the sidebar by swiping to the left the sidebar and the blog + * @return {void} + */ + closeSidebar: function() { + this.swipeSidebarToLeft(); + this.swipeBlogToLeft(); + }, + + /** + * Reset sidebar position + * @return {void} + */ + resetSidebarPosition: function() { + this.$sidebar.removeClass('pushed'); + }, + + /** + * Reset blog position + * @return {void} + */ + resetBlogPosition: function() { + this.$blog.removeClass('pushed'); + }, + + /** + * Swipe the sidebar to the right + * @return {void} + */ + swipeSidebarToRight: function() { + var self = this; + // Check if the sidebar isn't swiped + // and prevent multiple click on the open button with `.processing` class + if (!this.$sidebar.hasClass('pushed') && !this.$sidebar.hasClass('processing')) { + // Swipe the sidebar to the right + this.$sidebar.addClass('processing pushed'); + // add overflow on body to remove horizontal scroll + this.$body.css('overflow-x', 'hidden'); + setTimeout(function() { + self.$sidebar.removeClass('processing'); + }, 250); + } + }, + + /** + * Swipe the sidebar to the left + * @return {void} + */ + swipeSidebarToLeft: function() { + // Check if the sidebar is swiped + // and prevent multiple click on the close button with `.processing` class + if (this.$sidebar.hasClass('pushed') && !this.$sidebar.hasClass('processing')) { + // Swipe the sidebar to the left + this.$sidebar.addClass('processing').removeClass('pushed processing'); + // go back to the default overflow + this.$body.css('overflow-x', 'auto'); + } + }, + + /** + * Swipe the blog to the right + * @return {void} + */ + swipeBlogToRight: function() { + var self = this; + // Check if the blog isn't swiped + // and prevent multiple click on the open button with `.processing` class + if (!this.$blog.hasClass('pushed') && !this.$blog.hasClass('processing')) { + // Swipe the blog to the right + this.$blog.addClass('processing pushed'); + + setTimeout(function() { + self.$blog.removeClass('processing'); + }, 250); + } + }, + + /** + * Swipe the blog to the left + * @return {void} + */ + swipeBlogToLeft: function() { + var self = this; + // Check if the blog is swiped + // and prevent multiple click on the close button with `.processing` class + if (self.$blog.hasClass('pushed') && !this.$blog.hasClass('processing')) { + // Swipe the blog to the left + self.$blog.addClass('processing').removeClass('pushed'); + + setTimeout(function() { + self.$blog.removeClass('processing'); + }, 250); + } + } + }; + + $(document).ready(function() { + var sidebar = new Sidebar(); + sidebar.run(); + }); +})(jQuery); diff --git a/src/js/smartresize.js b/src/js/smartresize.js new file mode 100755 index 0000000..3b51497 --- /dev/null +++ b/src/js/smartresize.js @@ -0,0 +1,33 @@ +(function($, sr) { + // debouncing function from John Hann + // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ + var debounce = function(func, threshold, execAsap) { + var timeout; + + return function debounced() { + var obj = this; + var args = arguments; + + function delayed() { + if (!execAsap) { + func.apply(obj, args); + } + + timeout = null; + } + + if (timeout) { + clearTimeout(timeout); + } + else if (execAsap) { + func.apply(obj, args); + } + + timeout = setTimeout(delayed, threshold || 100); + }; + }; + + jQuery.fn[sr] = function(fn) { + return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); + }; +})(jQuery, 'smartresize'); diff --git a/src/js/tabbed-codeblocks.js b/src/js/tabbed-codeblocks.js new file mode 100755 index 0000000..234901a --- /dev/null +++ b/src/js/tabbed-codeblocks.js @@ -0,0 +1,41 @@ +(function($) { + 'use strict'; + + // Animate tabs of tabbed code blocks + + /** + * TabbedCodeBlock + * @param {String} elems + * @constructor + */ + var TabbedCodeBlock = function(elems) { + this.$tabbedCodeBlocs = $(elems); + }; + + TabbedCodeBlock.prototype = { + /** + * Run TabbedCodeBlock feature + * @return {void} + */ + run: function() { + var self = this; + self.$tabbedCodeBlocs.find('.tab').click(function() { + var $codeblock = $(this).parent().parent().parent(); + var $tabsContent = $codeblock.find('.tabs-content').children('pre, .highlight'); + // remove `active` css class on all tabs + $(this).siblings().removeClass('active'); + // add `active` css class on the clicked tab + $(this).addClass('active'); + // hide all tab contents + $tabsContent.hide(); + // show only the right one + $tabsContent.eq($(this).index()).show(); + }); + } + }; + + $(document).ready(function() { + var tabbedCodeBlocks = new TabbedCodeBlock('.codeblock--tabbed'); + tabbedCodeBlocks.run(); + }); +})(jQuery); diff --git a/src/js/tags-filter.js b/src/js/tags-filter.js new file mode 100755 index 0000000..967e799 --- /dev/null +++ b/src/js/tags-filter.js @@ -0,0 +1,136 @@ +(function($) { + 'use strict'; + + // Filter posts by using their categories on categories page : `/categories` + + /** + * TagsFilter + * @param {String} tagsArchivesElem + * @constructor + */ + var TagsFilter = function(tagsArchivesElem) { + this.$form = $(tagsArchivesElem).find('#filter-form'); + this.$inputSearch = $(tagsArchivesElem + ' #filter-form input[name=tag]'); + this.$archiveResult = $(tagsArchivesElem).find('.archive-result'); + this.$tags = $(tagsArchivesElem).find('.tag'); + this.$posts = $(tagsArchivesElem).find('.archive'); + this.tags = tagsArchivesElem + ' .tag'; + this.posts = tagsArchivesElem + ' .archive'; + // Html data attribute without `data-` of `.archive` element which contains the name of tag + this.dataTag = 'tag'; + this.messages = { + zero: this.$archiveResult.data('message-zero'), + one: this.$archiveResult.data('message-one'), + other: this.$archiveResult.data('message-other') + }; + }; + + TagsFilter.prototype = { + /** + * Run TagsFilter feature + * @return {void} + */ + run: function() { + var self = this; + + // Detect keystroke of the user + self.$inputSearch.keyup(function() { + self.filter(self.getSearch()); + }); + + // Block submit action + self.$form.submit(function(e) { + e.preventDefault(); + }); + }, + + /** + * Get the search entered by user + * @returns {String} the name of tag entered by the user + */ + getSearch: function() { + return this.$inputSearch.val().toLowerCase(); + }, + + /** + * Show related posts form a tag and hide the others + * @param {String} tag - name of a tag + * @return {void} + */ + filter: function(tag) { + if (tag === '') { + this.showAll(); + this.showResult(-1); + } + else { + this.hideAll(); + this.showPosts(tag); + this.showResult(this.countTags(tag)); + } + }, + + /** + * Display results of the search + * @param {Number} numbTags - Number of tags found + * @return {void} + */ + showResult: function(numbTags) { + if (numbTags === -1) { + this.$archiveResult.html('').hide(); + } + else if (numbTags === 0) { + this.$archiveResult.html(this.messages.zero).show(); + } + else if (numbTags === 1) { + this.$archiveResult.html(this.messages.one).show(); + } + else { + this.$archiveResult.html(this.messages.other.replace(/\{n\}/, numbTags)).show(); + } + }, + + /** + * Count number of tags + * @param {String} tag + * @returns {Number} + */ + countTags: function(tag) { + return $(this.posts + '[data-' + this.dataTag + '*=\'' + tag + '\']').length; + }, + + /** + * Show all posts from a tag + * @param {String} tag - name of a tag + * @return {void} + */ + showPosts: function(tag) { + $(this.tags + '[data-' + this.dataTag + '*=\'' + tag + '\']').show(); + $(this.posts + '[data-' + this.dataTag + '*=\'' + tag + '\']').show(); + }, + + /** + * Show all tags and all posts + * @return {void} + */ + showAll: function() { + this.$tags.show(); + this.$posts.show(); + }, + + /** + * Hide all tags and all posts + * @return {void} + */ + hideAll: function() { + this.$tags.hide(); + this.$posts.hide(); + } + }; + + $(document).ready(function() { + if ($('#tags-archives').length) { + var tagsFilter = new TagsFilter('#tags-archives'); + tagsFilter.run(); + } + }); +})(jQuery); diff --git a/src/scss/base/_base.scss b/src/scss/base/_base.scss new file mode 100755 index 0000000..617eccf --- /dev/null +++ b/src/scss/base/_base.scss @@ -0,0 +1,194 @@ +html { + font-family: $font-family-base; + // equal to 10px, useful to use em and rem + font-size: 10px; + // Gives you better control of the font size when the first selected font is not available. + @include prefix(text-size-adjust, 100%, 'ms' 'webkit'); + // Overrides the highlight color shown when the user taps + //a link or a JavaScript clickable element in Safari on iPhone + @include prefix(tap-highlight-color, rgba(0, 0, 0, 0), 'webkit'); +} + +body { + width: 100%; + height: 100%; + margin: 0; + padding: 0; + background: white; + font-family: $font-family-base; + font-size: map-get($font-size, base); + line-height: $line-height-base; + letter-spacing: $letter-spacing-base; + // Improve smoothing of the font by adding subpixel in Safari + @include prefix(font-smoothing, subpixel-antialiased, 'webkit'); + + // Hide overflow-x when the sidebar is swiped + &.pushed { + overflow-x: hidden; + } +} + +h1, +h2, +h3, +h4, +h5, +h6 { + letter-spacing: -0.04em; + font-family: map-get($font-families, 'headings'); + font-weight: 700; + line-height: 1.45em; + color: #4a4a4a; +} + +h1, +h2, +h3 { + margin: 1em 0 1em 0; +} + +h4, +h5, +h6 { + margin: 1em 0 0.5em 0; +} + +// List each header with his font size +@each $key, $value in $headings-font-size { + #{$key} { + font-size: $value; + } +} + +p { + margin: 0 0 1.5em 0; +} + +ul, +ol, +dl { + margin: 0 0 0.5em 0; +} + +a { + &, + &:hover, + &:active, + &:visited { + cursor: pointer; + color: map-get($colors, link); + text-decoration: none; + } + &:hover { + color: map-get($colors, link); + text-decoration: underline; + } +} + +table { + width: 100%; + background: transparent; + border-collapse: collapse; + border-spacing: 0; + text-align: left; + + th { + padding: 5px 10px; + font-weight: bold; + border-bottom: 2px solid #909ba2; + } + td { + padding: 5px 10px; + } + tr { + &:nth-child(2n) { + background: #f7f8f8; + } + } +} + +hr { + margin: 1.5em 0 0; + outline: none; + border: none; + border-top: 1px solid #eef2f8; +} + +dl { + dt { + font-weight: bold; + } + dd { + margin-left: 0; + } +} + +// code block +pre > code { + display: block; + width: 100%; + box-sizing: border-box; + padding: 15px; + font-family: #{map-get($font-families, 'highlight')}; + border: none; + margin: 0; + // To override cursor attribute of `.tag` components + cursor: text; + overflow-x: auto; + line-height: map-get($highlight, line-height) + 0.4em; + font-size: map-get($highlight, font-size); +} + +// inline code +code { + font-size: map-get($font-size, medium); + display: inline-block; + font-family: map-get($font-families, 'code'); + font-weight: 400; + background-color: map-get($highlight, 'background'); + padding: 0 10px; +} + +acronym, +abbr { + border-bottom: 1px dotted $font-color-base; +} + +blockquote { + border-left: 3px solid map-get($colors, 'base'); + padding: 0 15px; + font-style: italic; + margin: 1.5em 0 0; + + cite { + &:before { + content: ' — '; + padding: 0 0.3em; + } + } + & > p:first-child { + margin: 0; + } +} + +// Reduce global font-size base and headings font size on small screen and down +@media #{$small-and-down} { + code { + font-size: map-get($font-size, medium) - $font-size-base-sm-screen-reduction-factor; + } + @each $key, $value in $headings-font-size { + #{$key} { + font-size: $value - $headings-font-size-sm-screen-reduction-factor; + } + } +} + +// Reduce global font-size base and headings font size on medium screen only +@media #{$medium-only} { + @each $key, $value in $headings-font-size { + #{$key} { + font-size: $value - $headings-font-size-md-screen-reduction-factor; + } + } +} +
\ No newline at end of file diff --git a/src/scss/components/_alert.scss b/src/scss/components/_alert.scss new file mode 100755 index 0000000..80d6d87 --- /dev/null +++ b/src/scss/components/_alert.scss @@ -0,0 +1,69 @@ +.alert { + position: relative; + text-align: left; + padding: 10px 15px; + min-height: 30px; + margin: 1em 0 0; + border: none; + border-left: 3px solid; + p { + margin: 1.5em 0 0; + + &:first-child { + margin: 0; + } + } + &:not(.no-icon) { + padding-left: 55px; + + &:before { + position: absolute; + top: 10px; + left: 15px; + font-family: 'FontAwesome'; + font-size: 2.5rem; + } + } + &.info { + border-color: map-get($colors, 'primary'); + background-color: lighten(map-get($colors, 'primary'), 37%); + + &:not(.no-icon) { + &:before { + content: "\f05a"; + color: map-get($colors, 'primary'); + } + } + } + &.success { + border-color: map-get($colors, 'success'); + background-color: lighten(map-get($colors, 'success'), 42%); + content: "\f058"; + &:not(.no-icon) { + &:before { + content: "\f058"; + color: map-get($colors, 'success'); + } + } + } + &.warning { + border-color: map-get($colors, 'warning'); + background-color: lighten(map-get($colors, 'warning'), 42%); + &:not(.no-icon) { + &:before { + content: "\f071"; + color: map-get($colors, 'warning'); + } + } + } + &.danger { + border-color: map-get($colors, 'danger'); + background-color: lighten(map-get($colors, 'danger'), 42%); + &:not(.no-icon) { + &:before { + content: "\f05e"; + color: map-get($colors, 'danger'); + } + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_archive.scss b/src/scss/components/_archive.scss new file mode 100755 index 0000000..813b6de --- /dev/null +++ b/src/scss/components/_archive.scss @@ -0,0 +1,36 @@ +.archive-result { + display: none; +} + +.archive { + .archive-title { + color: $font-color-base; + + &:hover { + text-decoration: underline; + } + } + .archive-posts { + list-style: none; + + .archive-post { + .archive-post-title { + margin-left: 10px; + color: $font-color-base; + + &:hover { + text-decoration: underline; + } + } + .archive-post-date { + color: map-get($colors, light); + } + // Change styl of the list by adding font-awesome icon + &::before { + font-family: 'FontAwesome'; + content: '\f0da'; + font-size: map-get($font-size, small); + } + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_box.scss b/src/scss/components/_box.scss new file mode 100755 index 0000000..771af92 --- /dev/null +++ b/src/scss/components/_box.scss @@ -0,0 +1,14 @@ +// Group of `.box` +// Add margin when `.box` are in `.box-group` +.boxes { + margin-top: 20px; + + .box:nth-child(n + 2) { + margin-top: 20px; + } +} + +// Box +.box { + border-bottom: 1px solid #eef2f8; +}
\ No newline at end of file diff --git a/src/scss/components/_button.scss b/src/scss/components/_button.scss new file mode 100755 index 0000000..c45681c --- /dev/null +++ b/src/scss/components/_button.scss @@ -0,0 +1,52 @@ +.btn { + width: auto; + height: auto; + background: white; + border-radius: 3px; + padding: 8px 15px; + margin: 0; + letter-spacing: $letter-spacing-base; + font-size: $font-size-base; + cursor: pointer; + + &:hover, + &:focus, + &:active { + text-decoration: none; + } +} + +// Disabled button +.btn--disabled, +.btn--disabled:hover { + color: lighten(map-get($colors, light), 10) !important; + border: 1px solid lighten(map-get($colors, light), 10); + cursor: not-allowed; + text-decoration: none; +} + +// Color variant +.btn--default { + @include button-color-variant(map-get($colors, light)); +} + +.btn--success { + @include button-color-variant(map-get($colors, success)); +} + +.btn--primary { + @include button-color-variant(map-get($colors, primary)); +} + +.btn--danger { + @include button-color-variant(map-get($colors, danger)); +} + +// Size variant +.btn--medium { + @include button-size-variant(map-get($font-size, medium), 8px 15px); +} + +.btn--small { + @include button-size-variant(map-get($font-size, small), 8px 15px); +}
\ No newline at end of file diff --git a/src/scss/components/_caption.scss b/src/scss/components/_caption.scss new file mode 100755 index 0000000..3f9bb1f --- /dev/null +++ b/src/scss/components/_caption.scss @@ -0,0 +1,10 @@ +.caption { + display: block; + font-family: map-get($font-families, 'caption'); + font-size: map-get($font-size, small); + color: darken(map-get($colors, 'light'), 10%); + text-align: center; + font-style: italic; + padding-right: 10px; + padding-left: 10px; +}
\ No newline at end of file diff --git a/src/scss/components/_code.scss b/src/scss/components/_code.scss new file mode 100755 index 0000000..f108d94 --- /dev/null +++ b/src/scss/components/_code.scss @@ -0,0 +1,107 @@ +// Highlight code block +figure.highlight, +.codeblock { + margin: 10px 0; + line-height: map-get($highlight, line-height); + padding-top: 15px; + padding-bottom: 15px; + overflow: hidden; + + table { + display: block; + width: 100%; + } + + // Reset for tag `pre` and for class `.gutter`, `.code`, `.tag` + pre, + .gutter, + .code, + .tag { + background-color: inherit; + font-family: #{map-get($font-families, 'highlight')}; + border: none; + padding: 0; + margin: 0; + // To override cursor attribute of `.tag` components + cursor: text; + } + // To align line number and line of code regardless if there is a scroll bar or not + .gutter, + .code { + vertical-align: top; + } + // hide gutter when code is plain text + &.plain { + .gutter { + display: none; + } + } + // Meta bar which contains name of the file and his link + figcaption { + font-size: 1.3rem; + padding: 0 15px 20px; + margin: 0; + + a { + float: right; + } + } + + // Gutter which contains line numbers + .gutter { + border-right: map-get($highlight, border); + padding: 0.3em 15px; + } + // Code container + .code { + padding: 0.3em 15px 0.3em 1em; + width: 100%; + + pre { + max-width: calc(#{map-get($main-content, 'max-width')} - 50px); + overflow-x: auto; + overflow-y: hidden; + } + } + // All lines in gutter and code container + .line { + height: map-get($highlight, line-height); + font-size: map-get($highlight, font-size); + } +} + +// Tabbed code block +.codeblock--tabbed { + figure.highlight, + pre > code { + margin-bottom: 0; + padding-bottom: 0; + } + figcaption { + a, span { + float: left !important; + } + .tabs { + float: right; + .tab { + cursor: pointer; + display: inline-block; + margin: 0 5px; + padding: 0 7px; + &:last-child { + margin-right: 0; + } + } + } + } +} + +// Gist +.gist { + .line, + .line-number { + font-family: map-get($font-families, 'highlight'); + font-size: 1em; + margin: 0 0 5px 0; + } +}
\ No newline at end of file diff --git a/src/scss/components/_figure.scss b/src/scss/components/_figure.scss new file mode 100755 index 0000000..33ac0d9 --- /dev/null +++ b/src/scss/components/_figure.scss @@ -0,0 +1,60 @@ +.figure { + &.clear { + clear: both; + } + &.center { + width: calc(100% - 4px); + margin: 2px auto; + + .fig-img { + margin: 2px auto; + } + } + &.left { + float: left; + margin: 2px; + } + &.right { + float: right; + margin: 2px; + } + &.fig-20 { + @extend .left; + width: calc(20% - 4px); + } + &.fig-25 { + @extend .left; + width: calc(25% - 4px); + } + &.fig-33 { + @extend .left; + width: calc(33.3% - 4px); + } + &.fig-50 { + @extend .left; + width: calc(50% - 4px); + } + &.fig-75 { + @extend .left; + width: calc(75% - 4px); + } + &.fig-100 { + width: calc(100% - 4px); + margin: 2px; + } + &.figure--fullWidth { + width: 100%; + .figure-img { + margin: 0 auto; + } + } +} + +// Hide caption of small pictures on small screen +@media #{$small-and-down} { + .fig-33, .fig-25, .fig-20 { + .caption { + display: none; + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_form.scss b/src/scss/components/_form.scss new file mode 100755 index 0000000..64e1471 --- /dev/null +++ b/src/scss/components/_form.scss @@ -0,0 +1,22 @@ +.form-control { + background: transparent; + width: 100%; + border: none; + outline: none; + color: map-get($colors, base); + font-weight: 300; + + &:hover, + &:focus { + outline: none; + } +} + + +// Input size variant +.input--large { + @include input-size-variant(auto, 10px 0, 18px, 21px); +} +.input--xlarge { + @include input-size-variant(auto, 10px 0, 25px, 30px); +}
\ No newline at end of file diff --git a/src/scss/components/_hide.scss b/src/scss/components/_hide.scss new file mode 100755 index 0000000..f9f0a17 --- /dev/null +++ b/src/scss/components/_hide.scss @@ -0,0 +1,32 @@ +// Hide element on all screens +.hide { + display: none; +} + +// Hide element on very small screen and down +@media #{$xsmall-and-down} { + .hide-xs { + display: none; + } +} + +// Hide element on small screen only +@media #{$small-only} { + .hide-sm { + display: none; + } +} + +// Hide element on medium screen only +@media #{$medium-only} { + .hide-md { + display: none; + } +} + +// Hide element on large screen and up +@media #{$large-and-up} { + .hide-lg { + display: none; + } +}
\ No newline at end of file diff --git a/src/scss/components/_highlight-text.scss b/src/scss/components/_highlight-text.scss new file mode 100755 index 0000000..8e5ff99 --- /dev/null +++ b/src/scss/components/_highlight-text.scss @@ -0,0 +1,39 @@ +.highlight-text { + display: inline; + padding: 3px; + + &.red { + background-color:map-get($highlight-text-bg-colors, 'red'); + } + &.green { + background-color:map-get($highlight-text-bg-colors, 'green'); + } + &.blue { + background-color:map-get($highlight-text-bg-colors, 'blue'); + } + &.purple { + background-color:map-get($highlight-text-bg-colors, 'purple'); + } + &.orange { + background-color:map-get($highlight-text-bg-colors, 'orange'); + } + &.yellow { + background-color:map-get($highlight-text-bg-colors, 'yellow'); + } + &.cyan { + background-color:map-get($highlight-text-bg-colors, 'cyan'); + } + &.primary { + background-color:map-get($highlight-text-bg-colors, 'primary'); + } + &.success { + background-color:map-get($highlight-text-bg-colors, 'success'); + } + &.warning { + background-color:map-get($highlight-text-bg-colors, 'warning'); + } + &.danger { + background-color:map-get($highlight-text-bg-colors, 'danger'); + } + +}
\ No newline at end of file diff --git a/src/scss/components/_icon.scss b/src/scss/components/_icon.scss new file mode 100755 index 0000000..e48c74d --- /dev/null +++ b/src/scss/components/_icon.scss @@ -0,0 +1,17 @@ +// Add margin to an element +// Specifically implement for font-awesome's icons to add space between icon and text in a button +.icon-mt { + margin-top: 10px; +} + +.icon-mr { + margin-right: 10px; +} + +.icon-mb { + margin-bottom: 10px; +} + +.icon-ml { + margin-left: 10px; +}
\ No newline at end of file diff --git a/src/scss/components/_image-gallery.scss b/src/scss/components/_image-gallery.scss new file mode 100755 index 0000000..10a067a --- /dev/null +++ b/src/scss/components/_image-gallery.scss @@ -0,0 +1,78 @@ +.image-gallery { + display: block; + position: relative; + height: auto; + overflow: hidden; + margin-bottom: 30px; + + .image-gallery-metabar { + position: absolute; + bottom: 0; + // width: (full with) - ((padding right-left of `.image-gallery-metabar` + 0.05em) * 4) to be responsive on all screen + width: calc(100% - (1.5em) * 2); + font-family: map-get($font-families, 'image-gallery'); + font-style: italic; + background: rgba(0, 0, 0, 0.75); + font-size: map-get($font-size, small); + color: white; + padding: 0.5em 1.5em; + // Use to go over all images of the gallery + z-index: 1; + } + .image-gallery-photos { + .photo-box { + float: left; + position: relative; + overflow: hidden; + display: none; + + &:first-child { + display: block; + width: 100%; + // 16:9 ratio, consider as height value + padding-bottom: 56.25%; + } + .photo-box-inner { + position: absolute; + overflow: hidden; + + .photo { + width: 100%; + cursor: -webkit-zoom-in; + cursor: -moz-zoom-in; + } + } + } + } + // Thumbnail image of gallery + // Used when image gallery contains more than 2 images + // You can change the style of image gallery by changing the following value + // Currently, it display one large image above 2 smaller images + // First image of the gallery + .image-gallery-photos--thumbnail { + // Display all images + .photo-box { + display: block; + width: 50%; + // Consider as height value + padding-bottom: 30%; + // Display First image in large + &:first-child { + width: 100%; + // Consider as height value + padding-bottom: 40%; + margin-bottom: $image-gallery-photos-margin; + } + // Resize seconde image minus space between 2 images + &:nth-child(2) { + margin-right: $image-gallery-photos-margin; + // width: 50% minus the space between 2 images + width: calc(50% - #{$image-gallery-photos-margin}); // Consider as height value + } + // Hide all other images after the 3 first + &:nth-child(n + 4) { + display: none; + } + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_link.scss b/src/scss/components/_link.scss new file mode 100755 index 0000000..df54206 --- /dev/null +++ b/src/scss/components/_link.scss @@ -0,0 +1,19 @@ +a.link-unstyled { + &, + &:hover, + &:active { + cursor: pointer !important; + color: inherit !important; + text-decoration: none !important; + } + a.link { + &, + &:hover, + &:active { + text-decoration: underline !important; + } + } +} +a.fancybox { + cursor: zoom-in !important; +}
\ No newline at end of file diff --git a/src/scss/components/_main-content.scss b/src/scss/components/_main-content.scss new file mode 100755 index 0000000..07c28f0 --- /dev/null +++ b/src/scss/components/_main-content.scss @@ -0,0 +1,7 @@ +.main-content-wrap { + display: block; + max-width: map-get($main-content, max-width); + margin: 0 auto; + padding-right: map-get($main-content, padding-right-left); + padding-left: map-get($main-content, padding-right-left); +}
\ No newline at end of file diff --git a/src/scss/components/_markdown.scss b/src/scss/components/_markdown.scss new file mode 100755 index 0000000..cf15a38 --- /dev/null +++ b/src/scss/components/_markdown.scss @@ -0,0 +1,32 @@ +// Set markdown headings font size on large screen and up +@media #{$large-and-up} { + .markdown { + @each $key, $value in $markdown-headings-font-size { + #{$key} { + font-size: $value; + } + } + } +} + +// Reduce global font-size base and headings font size on small screen and down +@media #{$small-and-down} { + .markdown { + @each $key, $value in $markdown-headings-font-size { + #{$key} { + font-size: $value - $markdown-headings-font-size-sm-screen-reduction-factor; + } + } + } +} + +// Reduce global font-size base and headings font size on medium screen only +@media #{$medium-only} { + .markdown { + @each $key, $value in $markdown-headings-font-size { + #{$key} { + font-size: $value - $markdown-headings-font-size-md-screen-reduction-factor; + } + } + } +} diff --git a/src/scss/components/_media.scss b/src/scss/components/_media.scss new file mode 100755 index 0000000..ec4c5c5 --- /dev/null +++ b/src/scss/components/_media.scss @@ -0,0 +1,23 @@ +.media { + &-body, + &-left { + display: table-cell; + vertical-align: top; + } + &-left { + float: left; + padding-right: 15px; + } + &-body { + width: 100%; + } + &-heading { + margin: 0 0 -5px; + } + &-meta { + color: map-get($colors, 'light'); + } + &-content { + color: map-get($colors, 'base'); + } +}
\ No newline at end of file diff --git a/src/scss/components/_modal.scss b/src/scss/components/_modal.scss new file mode 100755 index 0000000..0aca4f2 --- /dev/null +++ b/src/scss/components/_modal.scss @@ -0,0 +1,70 @@ +.modal-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + box-sizing: border-box; + z-index: map-get($z-indexes, 'c-modal'); +} + +.modal { + width: 100%; + height: 100%; + max-width: #{map-get($main-content, 'max-width')}; + box-sizing: border-box; + position: relative; + margin: 0 auto; + padding: 0; + overflow: hidden; + + &-header { + position: relative; + padding: 10px 15px 0; + background: white; + border-bottom: 1px solid #eef2f8; + } + &-body { + position: relative; + padding: 0 15px; + overflow-y: auto; + background: white; + } + &-footer { + height: 50px; + padding: 0 15px; + background: white; + border-top: 1px solid #eef2f8; + } + .close-button { + position: absolute; + // perfect position + top: 9px; + right: 15px; + color: $font-color-base; + cursor: pointer; + } +} + +.overlay { + display: none; + background: rgba(0, 0, 0, 0.50); + width: 100%; + height: 100%; + position: fixed; + top: 0; + left: 0; + z-index: map-get($z-indexes, 'c-overlay'); + overflow: hidden; +} + +@media #{$medium-and-up} { + .modal-container { + padding: 50px 0; + left: 50%; + transform: translateX(-50%); + } + .modal { + border-radius: 5px; + } +}
\ No newline at end of file diff --git a/src/scss/components/_pagination.scss b/src/scss/components/_pagination.scss new file mode 100755 index 0000000..0f7be25 --- /dev/null +++ b/src/scss/components/_pagination.scss @@ -0,0 +1,25 @@ +.pagination-bar { + height: auto; + width: 100%; + height: $pagination-height; + + .pagination { + height: $pagination-height; + line-height: $pagination-height; + display: block; + list-style: none; + padding: 0 10px; + width: auto; + + .pagination-prev, + .pagination-next { + float: left; + margin-right: 10px; + } + .pagination-number { + float: right; + font-size: map-get($font-size, small); + color: map-get($colors, light); + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_post-actions.scss b/src/scss/components/_post-actions.scss new file mode 100755 index 0000000..55ccba6 --- /dev/null +++ b/src/scss/components/_post-actions.scss @@ -0,0 +1,83 @@ +.post-actions-wrap { + height: 60px; + padding: 0; + line-height: 60px; + clear: both; + + ul.post-actions { + float: left; + padding-left: 0; + margin-top: 0; + list-style: none; + + li.post-action { + width: auto; + text-align: center; + } + } + // Post's navigation options + ul.post-action-nav { + // Best width for responsive post's navigation panel on small screen and up + width: 45%; + // On very small screen `.post-actions-nav` will be above `.post-actions-share` + z-index: map-get($z-indexes, c-post-bottom-bar) + 2; + + li.post-action { + float: left; + // Fix a bug on Firefox. the right part of button `previous` fall down without this `min-width` + min-width: 42px; + + &:last-child { + .post-action-btn { + margin-left: 15px; + } + } + } + } + // Post's share options + ul.post-action-share { + // 100% minus width of `.post-action-nav`, + // best width for responsive post's share panel on small screen and up + width: 55%; + // On very small screen `.post-actions-nav` will be above `.post-actions-share` + z-index: map-get($z-indexes, c-post-bottom-bar) + 1; + + li.post-action { + float: right; + + &:nth-child(n + 3) { + .post-action-btn { + margin-right: 15px; + } + } + } + } +} + +// Increase width of `.post-actions-share` on small screen +@media #{$small-and-down} { + .post-actions-wrap { + ul.post-action-nav { + // Best width for responsive post's navigation panel on small screen + width: 25%; + } + ul.post-action-share { + // Best width for responsive post's share panel on small screen + width: 75%; + } + } +} + +// Increase width of `.post-actions-nav` on very small screen +@media #{$xsmall-and-down} { + .post-actions-wrap { + ul.post-action-nav { + // Best width for responsive post's navigation panel on very small screen + width: 35%; + } + ul.post-action-share { + // Best width for responsive post's share panel on very small screen + width: 65%; + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_post-header-cover.scss b/src/scss/components/_post-header-cover.scss new file mode 100755 index 0000000..2c330ad --- /dev/null +++ b/src/scss/components/_post-header-cover.scss @@ -0,0 +1,219 @@ +.post-header { + .post-title { + margin: 0; + word-break: initial; + overflow: hidden; + + &:hover { + text-decoration: none; + } + } +} + +// Cover image displayed in single post view +// When post's `coverImage` variable is defined +.post-header-cover { + display: table; + position: relative; + // Fix the cover image to the top of the page + top: 0; + left: 0; + background-size: cover; + background-position: center; + background-repeat: no-repeat; + width: 100%; + padding: calc(#{map-get($header, 'height')} + 30px) 0 30px 0; + // 100% minus header high, minus padding-top, minus padding bottom and minus 4px for perfect pixels + height: 100%; + z-index: map-get($z-indexes, 'c-post-header-cover'); + // Sidebar animation + // Transition style (push) + transition: transform .25s ease-in-out; + -webkit-transition: -webkit-transform .25s ease-in-out; + // Eliminate any flickering of elements while they are in a state of being animated + -webkit-backface-visibility: hidden; + -webkit-perspective: 1000; + + .post-header { + display: table-cell; + vertical-align: middle; + + .post-title { + max-width: map-get($main-content, 'max-width'); + margin: 0 auto; + color: white; + text-shadow: 0 2px 0 rgba(0, 0, 0, 0.9); + margin-bottom: 20px; + + &:hover { + text-decoration: none; + } + } + // Post meta contains post's date, post's categories and tags + .post-meta { + max-width: map-get($main-content, 'max-width'); + font-family: map-get($font-families, 'post-meta'); + font-size: $font-size-base; + color: white !important; + font-weight: 400; + letter-spacing: 0.05em; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.9); + margin: 0 auto; + + a { + color: white; + } + } + } +} + +// Decrease height of cover image +.post-header-cover.post-header-cover--partial { + height: 60%; +} + +.post-header-cover-caption { + margin: 5px 0 50px 0; +} + +// Decrease the font size of the post's title on very small screen +@media #{$xsmall-and-down} { + .post-header-cover { + .post-header { + .post-title { + font-size: map-get($headings-font-size, h1); + } + } + } +} + +// Increase the font size of the post's title on small screen +@media #{$small-only} { + .post-header-cover { + .post-header { + .post-title { + font-size: map-get($headings-font-size, h1) + 0.5rem; + } + } + } +} + +@media #{$small-and-down} { + .post-header-cover { + // Display post header cover div in large size + @include post-header-cover-lg; + + // Push post header cover div from the size of the large sidebar + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="4"], + &[data-behavior="5"] { + @include post-header-cover-pushed-lg; + } + // Push post header cover div from the size of the medium sidebar + &[data-behavior="3"], + &[data-behavior="6"] { + @include post-header-cover-pushed-md; + } + } +} + +@media #{$medium-only} { + // Increase the font size of the post's title on medium screen + .post-header-cover { + .post-header { + .post-title { + font-size: map-get($headings-font-size, h1) + 3rem; + line-height: 1.3em; + } + } + // Display post header cover div in medium size + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="3"] { + @include post-header-cover-md; + } + // Display post header cover div in large size and push it from the size of the large sidebar + &[data-behavior="4"], + &[data-behavior="5"] { + @include post-header-cover-lg; + @include post-header-cover-pushed-lg; + } + // Display post header cover div in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include post-header-cover-lg; + @include post-header-cover-pushed-md; + } + } +} + +@media #{$large-only} { + // Increase the font size of the post's title on large screen + .post-header-cover { + .post-header { + .post-title { + font-size: map-get($headings-font-size, h1) + 3.7rem; + line-height: 1.3em; + } + } + // Display post header cover div in small size + &[data-behavior="1"], + &[data-behavior="2"] { + @include post-header-cover-sm; + } + // Display post header cover div in medium size + &[data-behavior="3"] { + @include post-header-cover-md; + } + // Display post header cover div in large size and push it from the size of the large sidebar + &[data-behavior="4"], + &[data-behavior="5"] { + @include post-header-cover-lg; + @include post-header-cover-pushed-lg; + } + // Display post header cover div in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include post-header-cover-lg; + @include post-header-cover-pushed-md; + } + } +} + +@media #{$xlarge-and-up} { + // Increase the font size of the post's title on large screen + .post-header-cover { + .post-header { + .post-title { + font-size: map-get($headings-font-size, h1) + 3.7rem; + line-height: 1.3em; + } + } + // Display post header cover div in extra small size + &[data-behavior="1"] { + @include post-header-cover-xs; + } + // Display post header cover div in small size + &[data-behavior="2"] { + @include post-header-cover-sm; + } + // Display post header cover div in medium size + &[data-behavior="3"] { + @include post-header-cover-md; + } + // Display post header cover div in large size and push it from the size of the large sidebar + &[data-behavior="4"] { + @include post-header-cover-lg; + @include post-header-cover-pushed-xlg; + } + // Display post header cover div in large size and push it from the size of the extra large sidebar + &[data-behavior="5"] { + @include post-header-cover-lg; + @include post-header-cover-pushed-lg; + } + // Display post header cover div in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include post-header-cover-lg; + @include post-header-cover-pushed-md; + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_post.scss b/src/scss/components/_post.scss new file mode 100755 index 0000000..b0a34bb --- /dev/null +++ b/src/scss/components/_post.scss @@ -0,0 +1,88 @@ +.post { + position: relative; + width: 100%; + display: inline-block; + vertical-align: top; + + .post-header { + .post-title { + margin: 0; + word-break: initial; + overflow: hidden; + + &:hover { + text-decoration: none; + } + } + } + // Post meta contains post's date, post's categories and tags + .post-meta { + line-height: 1.5em; + font-family: map-get($font-families, 'post-meta'); + font-size: map-get($font-size, small); + font-weight: 400; + color: map-get($colors, light); + + a { + color: map-get($colors, light); + } + } + .post-content { + text-rendering: optimizelegibility; + letter-spacing: -0.3px; + font-family: map-get($font-families, 'post-content'); + color: map-get($colors, base); + margin-top: 20px; + font-weight: 400; + overflow: hidden; + @include prefix('hypens', 'auto', 'webkit' 'moz'); + + img { + display: block; + width: auto; + max-width: 100%; + } + :not(blockquote):not(.alert) { + & > p { + margin: 1.5em 0 0 0; + } + } + } + .post-footer { + margin-top: 20px; + &-tags { + padding-bottom: 10px; + margin-bottom: 10px; + border-bottom: 1px solid #eef2f8; + } + } +} + +// Increase the font size of the post's title on medium screen (only for single post view) +@media #{$medium-only} { + .post { + .post-header { + .post-title { + font-size: map-get($headings-font-size, h1) + 0.5rem; + } + } + } +} + +// Increase font size of the post's title on large screen (only for single post view) +@media #{$large-and-up} { + .post { + .post-header { + .post-title { + font-size: map-get($headings-font-size, h1) + 0.9rem; + } + } + } +} + +// Increase font-size on medium and large screen +@media #{$medium-and-up} { + .post-content { + font-size: 1.7rem; + } +}
\ No newline at end of file diff --git a/src/scss/components/_postShorten.scss b/src/scss/components/_postShorten.scss new file mode 100755 index 0000000..83725df --- /dev/null +++ b/src/scss/components/_postShorten.scss @@ -0,0 +1,156 @@ +// Group of `.postShorten` +// Add margin and border bottom when `.postShorten` are in `.postShorten-group` +.postShorten-group { + .postShorten { + // Space between 2 shorten post + margin-top: 15px; + border-bottom: 1px solid #eef2f8; + } +} + +// Post +.postShorten { + position: relative; + width: 100%; + display: inline-block; + vertical-align: top; + + .postShorten-thumbnailimg { + overflow:hidden; + } + .postShorten-header { + .postShorten-title { + margin: 0; + word-break: initial; + overflow: hidden; + + &:hover { + text-decoration: none; + } + } + } + // postShorten meta contains post's date, post's categories and tags + .postShorten-meta { + line-height: 1.5em; + + a { + color: map-get($colors, light); + } + } + .postShorten-meta, + .postShorten-readingtime { + color: map-get($colors, light); + } + .postShorten-excerpt_link { + // Bring the post's link nearest of the excerpt + margin-top: -15px; + } + .postShorten-meta, + .postShorten-readingtime, + .postShorten-excerpt_link { + font-family: map-get($font-families, 'post-excerpt-link'); + font-size: map-get($font-size, small); + font-weight: 400; + } + .postShorten-excerpt, + .postShorten-content { + text-rendering: optimizelegibility; + letter-spacing: -0.3px; + font-family: map-get($font-families, 'post-content'); + color: map-get($colors, base); + font-weight: 400; + overflow: hidden; + @include prefix('hypens', 'auto', 'webkit' 'moz'); + + img { + display: block; + width: auto; + max-width: 100%; + } + } + .postShorten-excerpt { + margin-top: 15px; + } + .postShorten-content { + margin-top: 25px; + } +} + +// Hide the post's thumbnail image on very small screen and down +@media #{$xsmall-and-down} { + .postShorten { + .postShorten-thumbnailimg { + display: none; + + img { + display: none; + } + } + } +} + +// Display the post's thumbnail image on small screen and up +@media #{$small-and-up} { + .postShorten.postShorten--thumbnailimg-right { + .postShorten-thumbnailimg { + float: right; + margin: 5px 0 30px 15px; + + img { + display: block; + width: $post-thumbnail-image-width; + height: $post-thumbnail-image-width; + object-fit: cover; + overflow: hidden; + } + } + .postShorten-wrap { + float: left; + width: calc(100% - #{$post-thumbnail-image-width} - 20px); + } + } + .postShorten.postShorten--thumbnailimg-left { + .postShorten-thumbnailimg { + float: left; + margin: 5px 15px 30px 0; + + img { + display: block; + width: $post-thumbnail-image-width; + height: $post-thumbnail-image-width; + object-fit: cover; + overflow: hidden; + } + } + .postShorten-wrap { + float: right; + width: calc(100% - #{$post-thumbnail-image-width} - 20px); + } + } + .postShorten.postShorten--thumbnailimg-top { + .postShorten-thumbnailimg { + margin-top: 5px; + } + } + .postShorten.postShorten--thumbnailimg-bottom { + .postShorten-wrap { + display: block; + width: 100%; + } + .postShorten-excerpt > p { + margin-bottom: 0; + } + .postShorten-thumbnailimg { + + display: block; + width: 100%; + overflow: hidden; + margin: 15px 0 15px 0; + + img { + width: auto; + height: auto; + } + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_pullquote.scss b/src/scss/components/_pullquote.scss new file mode 100755 index 0000000..13c9038 --- /dev/null +++ b/src/scss/components/_pullquote.scss @@ -0,0 +1,20 @@ +.pullquote { + text-align: left; + font-style: italic; + margin: 1.5em 0 0; + + &.left { + width: 45%; + float: left; + margin: 1.5em 35px 1.5em 0; + } + &.right { + width: 45%; + float: right; + margin: 1.5em 0 1.5em 35px; + } + &.blur { + background-color: lighten(map-get($colors, 'base'), 54%); + } + +}
\ No newline at end of file diff --git a/src/scss/components/_share-options-bar.scss b/src/scss/components/_share-options-bar.scss new file mode 100755 index 0000000..95aba60 --- /dev/null +++ b/src/scss/components/_share-options-bar.scss @@ -0,0 +1,105 @@ +.share-options-bar { + position: fixed; + // height + border-top + // used to hide the div at the bottom of the window + bottom: -156px; + background: white; + height: 155px; + clear: both; + border-top: 1px solid #eef2f8; + transition: transform .25s ease-in-out; + z-index: map-get($z-indexes, 'c-share-options-bar'); + -webkit-transition: -webkit-transform .25s ease-in-out; + // use to animate the share option bar + &.opened { + @include prefix(transform, translate3d(0, -155px, 0), 'webkit' 'moz'); + } + + .share-options { + padding: 0; + margin: 0; + text-align: center; + list-style: none; + + .share-option { + &:first-child { + .share-option-btn { + padding: 20px 0 10px 0; + } + } + &:last-child { + .share-option-btn { + padding: 10px 0 20px 0; + } + } + .share-option-btn { + color: #6e7681; + display: block; + width: 100%; + padding: 10px 0 10px 0; + + .fa { + margin-right: 15px; + } + } + } + } +} + +// mask where the user can click to close the share options bar +.share-options-mask { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: none; + z-index: map-get($z-indexes, 'c-mask'); +} + +// Behavior of the share options bar on small screens +@media #{$small-and-down} { + .share-options-bar { + // Display bottom bar in large size + @include share-options-bar-lg; + } +} + +// Behavior of the share options bar on medium screens +@media #{$medium-only} { + .share-options-bar { + // Display share options bar in small size + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="3"] { + @include share-options-bar-md; + } + // Display share options bar in large size + &[data-behavior="4"], + &[data-behavior="5"], + &[data-behavior="6"] { + @include share-options-bar-lg; + } + } +} + +// Behavior of the share options bar on large screens +@media #{$large-and-up} { + .share-options-bar { + // Display share options bar in small size + &[data-behavior="1"], + &[data-behavior="2"]{ + @include share-options-bar-sm; + } + // Display share options bar in medium size + &[data-behavior="3"] { + @include share-options-bar-md; + } + // Display share options bar in large size + &[data-behavior="4"], + &[data-behavior="5"], + &[data-behavior="6"] { + @include share-options-bar-lg; + } + } +}
\ No newline at end of file diff --git a/src/scss/components/_tag.scss b/src/scss/components/_tag.scss new file mode 100755 index 0000000..c609486 --- /dev/null +++ b/src/scss/components/_tag.scss @@ -0,0 +1,45 @@ +a.tag, +.tag { + display: inline-block; + background: #fff; + width: auto; + height: auto; + border-radius: 3px; + letter-spacing: $letter-spacing-base; + cursor: pointer; + margin: 0; + margin-right: 4px; + margin-bottom: 7px; +} + +// Colors variant +a.tag--default, +.tag--default { + @include tag-color-variant(map-get($colors, light)); +} + +a.tag--success, +.tag--success { + @include tag-color-variant(map-get($colors, success)); +} + +a.tag--primary, +.tag--primary { + @include tag-color-variant(map-get($colors, primary)); +} + +a.tag--danger, +.tag--danger { + @include tag-color-variant(map-get($colors, danger)); +} + +// Size variant +a.tag--default, +.tag--default { + @include tag-size-variant(map-get($font-size, small), 4.5px 15px); +} + +a.tag--small, +.tag--small { + @include tag-size-variant(map-get($font-size, small), 2px 10px); +}
\ No newline at end of file diff --git a/src/scss/components/_text.scss b/src/scss/components/_text.scss new file mode 100755 index 0000000..1bc5919 --- /dev/null +++ b/src/scss/components/_text.scss @@ -0,0 +1,102 @@ +// Text alignment +.text-left { + text-align: left !important; +} + +.text-right { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +.text-justify { + text-align: justify !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +// Text transformation +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +// Text size +.text-xsmall { + font-size: map-get($font-size, xsmall) !important; +} + +.text-small { + font-size: map-get($font-size, small) !important; +} + +.text-medium { + font-size: map-get($font-size, medium) !important; +} + +.text-base { + font-size: $font-size-base !important; +} + +.text-large { + font-size: map-get($font-size, large) !important; +} + +.text-xlarge { + font-size: map-get($font-size, xlarge) !important; +} + +// Text style +.text-strong { + font-weight: 700 !important; +} + +.text-regular { + font-weight: 400 !important; +} + +.text-light { + font-weight: 300 !important; +} + +.text-italic { + font-style: italic !important; +} + +.text-underline { + text-decoration: underline !important; +} + +.text-underline-hover { + &:hover { + text-decoration: underline !important; + } +} + +// Text coloration +.text-color-base { + color: map-get($colors, base) !important; +} + +.text-color-light { + color: map-get($colors, light) !important; +} + +.text-color-link { + color: map-get($colors, link) !important; +} + +.font-merryweather { + font-family: $merriweather-serif; +}
\ No newline at end of file diff --git a/src/scss/components/_tooltip.scss b/src/scss/components/_tooltip.scss new file mode 100755 index 0000000..c619199 --- /dev/null +++ b/src/scss/components/_tooltip.scss @@ -0,0 +1,166 @@ +// The default position of a tooltip is at the top of the focused element +.tooltip { + position: relative; + cursor: pointer; + // Add default behavior from `tooltip--top` + @extend .tooltip--top; + + &:before { + z-index: map-get($z-indexes, c-tooltip); + border: 6px solid transparent; + background: transparent; + content: ""; + } + &:after { + z-index: map-get($z-indexes, c-tooltip); + padding: 8px; + // Fixed width of tooltip + min-width: map-get($tooltip, min-width); + background-color: map-get($tooltip, background); + color: #fff; + content: attr(data-tooltip); + font-size: 0.93em; + line-height: $line-height-base; + border-radius: 5px; + } + &:before, + &:after { + position: absolute; + visibility: hidden; + @include opacity(0); + // Animate tooltip + -webkit-transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out, -webkit-transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24); + -moz-transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out, -moz-transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24); + transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out, transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24); + @include prefix(transform, translate3d(0, 0, 0), 'webkit' 'moz' 'ms'); + pointer-events: none; + } + + &:hover:before, + &:hover:after, + &:focus:before, + &:focus:after { + visibility: visible; + @include opacity(1); + // Animate tooltip + @include prefix(transform, translateY(-12px), 'webkit' 'moz' 'ms' 'o'); + } +} + +[data-tooltip] { + @extend .tooltip; +} + +// Directions +// Position tooltip at the top of the focused element +.tooltip--top { + &:before { + // Let's appear perfectly tooltip's arrow + margin-bottom: -#{map-get($tooltip, arrow-height)}; + border-top-color: map-get($tooltip, background); + } + &:after { + // Center tooltip with his arrow + margin-left: -#{(map-get($tooltip, min-width) / 2) + 1}; + } + &:before, + &:after { + // Position tooltip at the right of the focused element + bottom: 100%; + // Horizontally center tooltip's arrow relative to the focused element + left: calc(50% - (#{map-get($tooltip, arrow-width)} / 2)); + } + &:hover:before, + &:hover:after, + &:focus:before, + &:focus:after { + // Translate tooltip to the top + @include prefix(transform, translateY(-12px), 'webkit' 'moz' 'ms' 'o'); + } +} + +// Position tooltip at the left of the focused element +.tooltip--left { + &:before { + margin-left: 0; + margin-right: -#{map-get($tooltip, arrow-height)}; + margin-bottom: 0; + border-top-color: transparent; + border-left-color: map-get($tooltip, background); + } + &:after { + margin-left: 0; + // Vertically center tooltip content + margin-bottom: -#{map-get($tooltip, arrow-width)}; + } + &:before, + &:after { + // Position arrow at the left of the focused element + right: 100%; + // Vertically center tooltip's arrow relative to the focused element + bottom: calc(50% - (#{map-get($tooltip, arrow-width)} / 2)); + left: auto; + } + &:hover:before, + &:hover:after, + &:focus:before, + &:focus:after { + // Translate tooltip to the left + @include prefix(transform, translateX(-12px), 'webkit' 'moz' 'ms' 'o'); + } +} + +// Position tooltip at the bottom of the focused element +.tooltip--bottom { + &:before { + margin-top: -#{map-get($tooltip, arrow-height)}; + margin-bottom: 0; + border-top-color: transparent; + border-bottom-color: map-get($tooltip, background); + } + &:before, + &:after { + // Position arrow at the bottom of the focused element + top: 100%; + bottom: auto; + // Horizontally center tooltip's arrow relative to the focused element + left: calc(50% - (#{map-get($tooltip, arrow-width)} / 2)); + } + &:hover:before, + &:hover:after, + &:focus:before, + &:focus:after { + // Translate tooltip to the bottom + @include prefix(transform, translateY(12px), 'webkit' 'moz' 'ms' 'o'); + } +} + +// Position tooltip at the right of the focused element +.tooltip--right { + &:before { + margin-bottom: 0; + margin-left: -#{map-get($tooltip, arrow-height)}; + border-top-color: transparent; + border-right-color: map-get($tooltip, background); + } + &:after { + margin-left: 0; + // Vertically center tooltip content + margin-bottom: -#{map-get($tooltip, arrow-width)}; + } + &:before, + &:after { + // Vertically center tooltip's arrow relative to the focused element + bottom: calc(50% - (#{map-get($tooltip, arrow-width)} / 2)); + // Position arrow at the right of the focused element + left: 100%; + right: auto; + } + &:hover:before, + &:hover:after, + &:focus:before, + &:focus:after { + // Translate tooltip to the right + @include prefix(transform, translateX(12px), 'webkit' 'moz' 'ms' 'o'); + } +}
\ No newline at end of file diff --git a/src/scss/components/_video.scss b/src/scss/components/_video.scss new file mode 100755 index 0000000..c68267f --- /dev/null +++ b/src/scss/components/_video.scss @@ -0,0 +1,20 @@ +// Responsive video container +.video-container { + position: relative; + height: 0; + overflow: hidden; + // 16:9 ratio, consider as height value + padding-bottom: 56.25%; + margin: 0 0 1.75em 0; + + iframe, + object, + embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin-top: 0; + } +}
\ No newline at end of file diff --git a/src/scss/layouts/_about.scss b/src/scss/layouts/_about.scss new file mode 100755 index 0000000..6d7bb91 --- /dev/null +++ b/src/scss/layouts/_about.scss @@ -0,0 +1,113 @@ +#about { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: map-get($about, background); + text-align: center; + line-height: 100%; + overflow-y: auto; + overflow-x: hidden; + z-index: map-get($z-indexes, l-about); + + #about-card { + position: relative; + // Position the card out the page to improve the javascript drop effect + top: -1000px; + display: block; + background: white; + max-width: 400px; + margin: 15px auto; + border-radius: 3px; + padding: 30px 0; + @include prefix(box-shadow, 0 0 5px rgba(0, 0, 0, 0.50), 'webkit' 'moz'); + + #about-btn-close { + position: absolute; + top: 15px; + right: 15px; + color: map-get($colors, light); + cursor: pointer; + + &:hover { + color: darken(map-get($colors, light), 15); + } + } + #about-card-picture { + margin-bottom: 15px; + } + #about-card-name { + margin-top: 0; + margin-bottom: 20px; + } + #about-card-bio { + padding: 0 30px; + margin: 0 0 30px 0; + } + #about-card-job, + #about-card-location { + display: inline-block; + vertical-align: top; + } + #about-card-job, + #about-card-location, + #about-card-bio { + font-size: $font-size-base; + line-height: $line-height-base; + font-weight: 400; + color: map-get($colors, base); + } + } +} + +// Improve responsiveness of about card on small screen and down +@media #{$small-and-down} { + #about { + #about-card { + width: 90%; + + #about-card-job, + #about-card-location { + display: block; + width: calc(100% - 60px); // 60px = padding right + padding left of `#about-card` + padding: 0 30px; + } + #about-card-picture { + width: 90px; + height: 90px; + border-radius: 45px; + } + #about-card-job { + margin-bottom: 15px; + } + } + } +} + +// Improve responsiveness of about card on medium screen and up +@media #{$medium-and-up} { + #about { + #about-card { + width: 80%; + #about-card-picture { + width: 110px; + height: 110px; + border-radius: 55px; + } + #about-card-job, + #about-card-location { + display: inline-block; + // 48px = padding right of `#about-card-job` + `#about-card-location` + width: calc((100% / 2) - 48px); + } + #about-card-job { + padding: 0 15px 0 30px; + } + #about-card-location { + padding: 0 30px 0 15px; + } + } + } +}
\ No newline at end of file diff --git a/src/scss/layouts/_blog.scss b/src/scss/layouts/_blog.scss new file mode 100755 index 0000000..03f16f9 --- /dev/null +++ b/src/scss/layouts/_blog.scss @@ -0,0 +1,7 @@ +#blog { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +}
\ No newline at end of file diff --git a/src/scss/layouts/_bottom-bar.scss b/src/scss/layouts/_bottom-bar.scss new file mode 100755 index 0000000..b4d5119 --- /dev/null +++ b/src/scss/layouts/_bottom-bar.scss @@ -0,0 +1,119 @@ +// bottom bar which contains navigation and share options +#bottom-bar { + display: none; + position: fixed; + bottom: 0; + height: 60px; + background: white; + margin: 0; + border-top: 1px solid #eef2f8; + padding: 0 15px; + z-index: map-get($z-indexes, c-post-bottom-bar); + transition: transform .25s ease-in-out; + -webkit-transition: -webkit-transform .25s ease-in-out; +} + +@media #{$small-and-down} { + #bottom-bar { + // Display bottom bar in large size + @include bottom-bar-lg; + + // Push the bottom bar from the size of the large sidebar + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="4"], + &[data-behavior="5"] { + @include bottom-bar-pushed-lg; + } + // Push the bottom bar from the size of the medium sidebar + &[data-behavior="3"], + &[data-behavior="6"] { + @include bottom-bar-pushed-md; + } + } +} + +@media #{$medium-only} { + #bottom-bar { + // Display bottom bar in medium size and push it from the size of the medium sidebar + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="3"] { + @include bottom-bar-md; + @include bottom-bar-pushed-md; + } + // Display bottom bar in large size and push it from the size of the large sidebar + &[data-behavior="4"], + &[data-behavior="5"] { + @include bottom-bar-lg; + @include bottom-bar-pushed-lg; + } + // Display bottom bar in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include bottom-bar-lg; + @include bottom-bar-pushed-md; + } + } +} + +@media #{$large-only} { + #bottom-bar { + // Display bottom bar in small size and push it from the size of the large sidebar + &[data-behavior="1"], + &[data-behavior="2"] { + @include bottom-bar-sm; + @include bottom-bar-pushed-lg; + } + // Display bottom bar in medium size and push it from the size of the medium sidebar + &[data-behavior="3"] { + @include bottom-bar-md; + @include bottom-bar-pushed-md; + } + // Display bottom bar in large size and push it from the size of the large sidebar + &[data-behavior="4"], + &[data-behavior="5"] { + @include bottom-bar-lg; + @include bottom-bar-pushed-lg; + } + // Display bottom bar in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include bottom-bar-lg; + @include bottom-bar-pushed-md; + } + } +} + +@media #{$xlarge-and-up} { + #bottom-bar { + // Display bottom bar in extra small size and push it from the size of the extra large sidebar + &[data-behavior="1"] { + @include bottom-bar-xs; + @include bottom-bar-pushed-xlg; + } + // Display bottom bar in small size and push it from the size of the large sidebar + &[data-behavior="2"] { + @include bottom-bar-sm; + @include bottom-bar-pushed-lg; + } + // Display bottom bar in medium size and push it from the size of the medium sidebar + &[data-behavior="3"] { + @include bottom-bar-md; + @include bottom-bar-pushed-md; + } + // Display bottom bar in large size and push it from the size of the extra large sidebar + &[data-behavior="4"] { + @include bottom-bar-lg; + @include bottom-bar-pushed-xlg; + } + // Display bottom bar in large size and push it from the size of the extra large sidebar + &[data-behavior="5"] { + @include bottom-bar-lg; + @include bottom-bar-pushed-lg; + } + // Display bottom bar in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include bottom-bar-lg; + @include bottom-bar-pushed-md; + } + } +}
\ No newline at end of file diff --git a/src/scss/layouts/_cover.scss b/src/scss/layouts/_cover.scss new file mode 100755 index 0000000..f198323 --- /dev/null +++ b/src/scss/layouts/_cover.scss @@ -0,0 +1,11 @@ +#cover { + position: fixed; + width: 100%; + height: 100%; + background-repeat: no-repeat; + background-size: cover; + top: 0; + left: 0; + // position the cover below the whole blog + z-index: map-get($z-indexes, l-cover); +}
\ No newline at end of file diff --git a/src/scss/layouts/_footer.scss b/src/scss/layouts/_footer.scss new file mode 100755 index 0000000..09f1fad --- /dev/null +++ b/src/scss/layouts/_footer.scss @@ -0,0 +1,8 @@ +#footer { + color: map-get($colors, light); + font-size: map-get($font-size, medium); + text-align: center; + margin-top: 70px; + height: auto; + padding: 20px 20px; +}
\ No newline at end of file diff --git a/src/scss/layouts/_header.scss b/src/scss/layouts/_header.scss new file mode 100755 index 0000000..dc71569 --- /dev/null +++ b/src/scss/layouts/_header.scss @@ -0,0 +1,112 @@ +#header { + display: block; + width: 100%; + height: map-get($header, height); + background: map-get($header, background); + position: fixed; + top: 0; + border: map-get($header, border); + color: map-get($header, color); + // used to animate the header on small screen with javascript + //@include prefix(transition, top 0.25s ease-in-out, 'webkit' 'moz' 'ms' 'o'); + z-index: map-get($z-indexes, l-header); + // Sidebar animation + // Transition style (push) + transition: transform .25s ease-in-out; + -webkit-transition: -webkit-transform .25s ease-in-out; + // Eliminate any flickering of elements while they are in a state of being animated + -webkit-backface-visibility: hidden; + -webkit-perspective: 1000; + + #btn-open-sidebar { + position: absolute; + // vertical center + top: 20px; + left: 20px; + cursor: pointer; + } + .header-right-picture { + position: absolute; + // vertical center + top: 12.5px; + right: 20px; + display: block; + width: 30px; + height: 30px; + color: map-get($header, color); + + .header-picture { + display: block; + width: 30px; + height: 30px; + border-radius: 15px; + } + } + .header-right-icon { + position: absolute; + // vertical center + top: 12.5px; + right: 20px; + color: map-get($header, color); + } + .header-title { + text-align: center; + font-size: $font-size-base; + line-height: 55px; + margin: 0; + + .header-title-link { + color: map-get($header, color); + font-weight: normal; + + &:hover, + &:active { + color: darken(map-get($header, color), 10); + text-decoration: none; + } + } + } + // Class used to swipe to the top the header on small screen when the user scroll down + &.header-up { + @include prefix(transform, translate3d(0, -#{map-get($header, height)}, 0), 'webkit' 'moz'); + } + + // Push the header from the size of the large sidebar + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="4"], + &[data-behavior="5"] { + @include header-pushed-lg; + } + + // Push the header from the size of the medium sidebar + &[data-behavior="3"], + &[data-behavior="6"] { + @include header-pushed-md; + } +} + +@media #{$medium-and-up} { + #header { + // Hide header + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="3"] { + display: none; + } + } +} + +// Push the header from the size of the extra large sidebar +@media #{$xlarge-and-up} { + #header { + &[data-behavior="1"], + &[data-behavior="4"] { + @include header-pushed-xlg; + } + &[data-behavior="2"], + &[data-behavior="5"] { + @include header-pushed-lg; + } + } +}
\ No newline at end of file diff --git a/src/scss/layouts/_main.scss b/src/scss/layouts/_main.scss new file mode 100755 index 0000000..782ae58 --- /dev/null +++ b/src/scss/layouts/_main.scss @@ -0,0 +1,127 @@ +#main { + display: block; + min-height: 100%; + background: map-get($main, 'background-color'); + transition: transform .25s ease-in-out; + -webkit-transition: -webkit-transform .25s ease-in-out; + + &.hasCover { + // Set `padding-top` to `50px` when there is a cover image on page and + // if there is a cover caption or + // if its meta information are out of cover image + &.hasCoverCaption, + &.hasCoverMetaOut { + padding-top: 50px !important; + } + + // Set `padding-top` to 0 when there is a cover image on page and + // if its meta information are on image or + // if its meta information are out of cover image and + // if there is a cover caption + // + // The cover caption have a `margin-top` to `50px` to replace the padding + &.hasCoverMetaIn, + &.hasCoverMetaOut.hasCoverCaption { + padding-top: 0 !important; + } + } +} + +@media #{$small-and-down} { + #main { + // Display `main` div in large size + @include main-lg; + + // Push `main` div from the size of the large sidebar + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="4"], + &[data-behavior="5"] { + @include main-pushed-lg; + } + // Push `main` div from the size of the medium sidebar + &[data-behavior="3"], + &[data-behavior="6"] { + @include main-pushed-md; + } + } +} + +@media #{$medium-only} { + #main { + // Display `main` div in medium size + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="3"] { + @include main-md; + } + // Display `main` div in large size and push it from the size of the large sidebar + &[data-behavior="4"], + &[data-behavior="5"] { + @include main-lg; + @include main-pushed-lg; + } + // Display `main` div in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include main-lg; + @include main-pushed-md; + } + } +} + +@media #{$large-only} { + #main { + // Display `main` div in small size + &[data-behavior="1"], + &[data-behavior="2"] { + @include main-sm; + } + // Display `main` div in medium size + &[data-behavior="3"] { + @include main-md; + } + // Display `main` div in large size and push it from the size of the large sidebar + &[data-behavior="4"], + &[data-behavior="5"]{ + @include main-lg; + @include main-pushed-lg; + } + // Display `main` div in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include main-lg; + @include main-pushed-md; + } + } +} + +@media #{$xlarge-and-up} { + #main { + // Display `main` div in extra small size + &[data-behavior="1"] { + @include main-xs; + } + // Display `main` div in small size + &[data-behavior="2"] { + @include main-sm; + } + // Display `main` div in medium size + &[data-behavior="3"] { + @include main-md; + } + // Display `main` div in large size and push it from the size of the extra large sidebar + &[data-behavior="4"] { + @include main-lg; + @include main-pushed-xlg; + } + // Display `main` div in large size and push it from the size of the extra large sidebar + &[data-behavior="5"] { + @include main-lg; + @include main-pushed-lg; + } + // Display `main` div in large size and push it from the size of the medium sidebar + &[data-behavior="6"] { + @include main-lg; + @include main-pushed-md; + } + } +}
\ No newline at end of file diff --git a/src/scss/layouts/_sidebar.scss b/src/scss/layouts/_sidebar.scss new file mode 100755 index 0000000..0275397 --- /dev/null +++ b/src/scss/layouts/_sidebar.scss @@ -0,0 +1,168 @@ +// Global CSS rules for all screen size +#sidebar { + font-family: map-get($font-families, 'sidebar'); + height: 100%; + position: fixed; + top: 0; + background: map-get($sidebar, background); + overflow: auto; + z-index: map-get($z-indexes, l-sidebar); + // Sidebar animation + // Transition style (push) + transition: transform .25s ease-in-out; + -webkit-transition: -webkit-transform .25s ease-in-out; + // Improve smoothing of the font by adding subpixel in Safari + @include prefix(font-smoothing, antialiased, 'webkit'); + + .sidebar-container { + overflow: auto; + } + // Author information + .sidebar-profile { + color: map-get($sidebar, color); + text-align: center; + padding-top: 18px; + margin-bottom: 15px; + + .sidebar-profile-picture { + display: block; + margin: 0 auto; + } + .sidebar-profile-name { + font-size: 1.1em; + color: map-get($sidebar, color); + } + } + // Sidebar's buttons + ul.sidebar-buttons { + padding: 0; + margin: 0 0 20px 0; + + li.sidebar-button { + display: block; + width: 100%; + // Height of a link in the menu + height: 45px; + line-height: 45px; + + .sidebar-button-link { + color: map-get($sidebar, color); + display: block; + height: 100%; + + &:hover, + &:active { + text-decoration: none; + color: lighten(map-get($sidebar, color), 35); + } + } + } + &:first-child { + margin-top: 5px; + } + } +} + +// Define sidebar behavior configured in `_config.yml` for small screen +// On `$small-and-down` (small screen): It hide by default the sidebar +// and with javascript located in `source/_js/_sidebar.js`, it will animate the swipe of the sidebar +@media #{$small-and-down} { + #sidebar { + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="4"], + &[data-behavior="5"] { + left: -#{map-get($sidebar, lg-screen-width)}; + @include sidebar-lg; + } + &[data-behavior="3"], + &[data-behavior="6"] { + left: -#{map-get($sidebar, md-screen-width)}; + @include sidebar-md; + } + } +} + +// Define sidebar behavior configured in `_config.yml` for medium screen +@media #{$medium-only} { + #sidebar { + &[data-behavior="1"], + &[data-behavior="2"], + &[data-behavior="3"] { + @include sidebar-md; + } + &[data-behavior="4"], + &[data-behavior="5"] { + left: -#{map-get($sidebar, lg-screen-width)}; + @include sidebar-lg; + } + &[data-behavior="6"] { + left: -#{map-get($sidebar, md-screen-width)}; + @include sidebar-md; + } + } +} + +// Define sidebar behavior configured in `_config.yml` for large screen +@media #{$large-only} { + #sidebar { + &[data-behavior="1"], + &[data-behavior="2"] { + @include sidebar-lg; + } + &[data-behavior="3"] { + @include sidebar-md; + } + &[data-behavior="4"], + &[data-behavior="5"] { + left: -#{map-get($sidebar, lg-screen-width)}; + @include sidebar-lg; + } + &[data-behavior="6"] { + left: -#{map-get($sidebar, md-screen-width)}; + @include sidebar-md; + } + } +} + +@media #{$xlarge-and-up} { + #sidebar { + &[data-behavior="1"] { + @include sidebar-xlg; + } + &[data-behavior="2"] { + @include sidebar-lg; + } + &[data-behavior="3"] { + @include sidebar-md; + } + &[data-behavior="4"] { + left: -#{map-get($sidebar, xlg-screen-width)}; + @include sidebar-xlg; + } + &[data-behavior="5"] { + left: -#{map-get($sidebar, lg-screen-width)}; + @include sidebar-lg; + } + &[data-behavior="6"] { + left: -#{map-get($sidebar, md-screen-width)}; + @include sidebar-md; + } + // hide bio in sidebar when small sidebar is enabled + &[data-behavior="2"], + &[data-behavior="3"], + &[data-behavior="5"], + &[data-behavior="6"] { + .sidebar-profile-bio { + display: none; + } + } + } +} + +// display author bio only on extra large screen +@media #{$large-and-down} { + #sidebar .sidebar-profile-bio { + display: none; + } +} diff --git a/src/scss/pages/_search.scss b/src/scss/pages/_search.scss new file mode 100755 index 0000000..26077d5 --- /dev/null +++ b/src/scss/pages/_search.scss @@ -0,0 +1,60 @@ +#algolia-search-modal { + display: none; + + .search-icon { + position: absolute; + top: 15px; + left: 15px; + color: $font-color-base; + } + .media-content { + font-size: 0.95em; + } + .search-input { + box-sizing: border-box; + padding: 0 130px 0 25px; + margin: 0; + } + .modal-header { + padding-bottom: 8px; + } + .modal-body { + padding-top: 15px; + // minus its padding and height of header bar and footer bar + height: calc(100% - 100px - 15px); + } + + .media:nth-child(n+2) { + padding-top: 15px; + } + hr { + margin-top: 0; + } + .results-count { + line-height: 50px; + color: $font-color-base; + } + .searchby-algolia { + position: absolute; + top: 15px; + right: 45px; + } + .searchby-algolia-text { + display: inline-block; + vertical-align: top; + line-height: 20px; + height: 20px; + } + .searchby-algolia-logo { + display: inline-block; + vertical-align: top; + height: 20px; + } + .no-result { + display: none; + position: relative; + top: 50%; + transform: translateY(-50%); + } +} + diff --git a/src/scss/themes/_hljs-custom.scss b/src/scss/themes/_hljs-custom.scss new file mode 100755 index 0000000..3da9e5f --- /dev/null +++ b/src/scss/themes/_hljs-custom.scss @@ -0,0 +1,51 @@ +// Highlight.js custom theme +// Follow guidelines +// 1. Uncomment the block just below - remove `/*` and `*/` +// 2. Fill `background`, `color`, `border-right-color` properties +// with properties of `.hljs` CSS class of your theme +// 3. Put your theme where it's indicated just below +// 4. Remove `.hljs {...}` rules +// 5. Remove `hljs-` of all CSS class name. E.g : `.hljs-comment` becomes `.comment` +// 6. Comment line 61 (`'themes/tranquilpeak',`) of `source/_css/tranquilpeak.scss` file +// 7. Run `grunt buildProd` to build the theme and see the result +/* +// Default code block +pre > code { + background: ; + color: ; +} + +// Default inline code +code { + background-color: ; +} + +// Tabbed code block tab +// If your theme is dark then use a lighter background +// to see clearly which tab is active +.codeblock--tabbed figcaption .tab.active { + background: ; + color: ; +} + +// highlight code block +figure.highlight, +.codeblock { + background: ; + color: ; + + figcaption { + background: ; + color: ; + } + .gutter { + background: ; + border-right-color: ; + .line { + color: ; + } + } + // PUT YOUR THEME HERE + +} +*/
\ No newline at end of file diff --git a/src/scss/themes/_hljs-tranquilpeak.scss b/src/scss/themes/_hljs-tranquilpeak.scss new file mode 100755 index 0000000..e374c7f --- /dev/null +++ b/src/scss/themes/_hljs-tranquilpeak.scss @@ -0,0 +1,556 @@ +// Official theme for Tranquilpeak +// Default code block +pre > code { + background: map-get($highlight, 'background'); + color: map-get($highlight-colors, night-rider); +} + +// Default inline code +code { + background-color: map-get($highlight, 'background'); +} + +// Tabbed code block tab +.codeblock--tabbed figcaption .tab.active { + background: map-get($colors, 'primary'); + color: white; +} + +// Highlight code block +figure.highlight, +.codeblock { + background: map-get($highlight, 'background'); + color: map-get($highlight-colors, night-rider); + + figcaption { + background: map-get($highlight, 'background'); + color: #999999; + } + .gutter { + background: map-get($highlight, 'background'); + border-right-color: #e6e6e6; + + .line { + color: #aaaaaa; + } + } + + // Highlight code coloration + // General + .comment { + color: map-get($highlight-colors, pewter); + } + .string { + color: map-get($highlight-colors, egyptian-blue); + } + .keyword { + color: map-get($highlight-colors, cardinal); + } + // ApacheConf + &.apacheconf .code { + .common, + .nomarkup, + .attribute, + .variable, + .cbracket, + .keyword { + color: map-get($highlight-colors, bondi-blue); + } + .sqbracket { + color: map-get($highlight-colors, persimmon); + } + .section, + .tag { + color: map-get($highlight-colors, asparagus); + } + } + // Bash + &.bash .code { + .shebang { + color: map-get($highlight-colors, pewter); + } + .literal, + .built_in { + color: map-get($highlight-colors, bondi-blue); + } + .variable { + color: map-get($highlight-colors, night-rider); + } + .title { + color: map-get($highlight-colors, scampi); + } + } + // coffescript + &.coffeescript .code { + .title { + color: map-get($highlight-colors, scampi); + } + .literal, + .built_in, + .number { + color: map-get($highlight-colors, bondi-blue); + } + .reserved, + .attribute { + color: map-get($highlight-colors, bahama-blue); + } + .subst, + .regexp, + .attribute { + color: map-get($highlight-colors, persimmon); + } + } + // C/C++ + &.cpp .code, + &.c .code { + .preprocessor { + color: map-get($highlight-colors, persimmon); + } + .meta-keyword { + color: map-get($highlight-colors, cardinal); + } + .title { + color: map-get($highlight-colors, scampi); + } + .number, + .built_in { + color: map-get($highlight-colors, bondi-blue); + } + } + // C# + &.cs .code { + .preprocessor, + .preprocessor .keyword { + color: map-get($highlight-colors, night-rider); + } + .title { + color: map-get($highlight-colors, scampi); + } + .number, + .built_in { + color: map-get($highlight-colors, bondi-blue); + } + .xmlDocTag, + .doctag { + color: map-get($highlight-colors, asparagus); + } + } + // CSS + &.css .code { + .at_rule, + .important, + .meta { + color: map-get($highlight-colors, cardinal); + } + .attribute, + .hexcolor, + .number, + .function { + color: map-get($highlight-colors, bondi-blue); + } + .attr_selector, + .value { + color: map-get($highlight-colors, night-rider); + } + .id, + .class, + .pseudo, + .selector-pseudo { + color: map-get($highlight-colors, scampi); + } + .tag, + .selector-tag { + color: map-get($highlight-colors, asparagus); + } + } + // Diff + &.diff .code { + .chunk, + .meta { + color: map-get($highlight-colors, scampi); + font-weight: bold; + } + .addition { + color: map-get($highlight-colors, limeade); + background-color: map-get($highlight-colors, 'honeydew'); + } + .deletion { + color: map-get($highlight-colors, free-speech-red); + background-color: map-get($highlight-colors, misty-rose); + } + } + // HTTP + &.http .code { + .attribute, + .attr { + color: map-get($highlight-colors, egyptian-blue); + } + .literal { + color: map-get($highlight-colors, bondi-blue); + } + .request { + color: map-get($highlight-colors, cardinal); + } + } + // INI + &.ini .code { + .title, + .section { + color: map-get($highlight-colors, scampi); + } + .setting, + .attr { + color: map-get($highlight-colors, cardinal); + } + .value, + .keyword { + color: map-get($highlight-colors, night-rider); + } + } + // JAVA + &.java .code { + .title { + color: map-get($highlight-colors, scampi); + } + .javadoc { + color: map-get($highlight-colors, pewter); + } + .meta, + .annotation, + .javadoctag { + color: map-get($highlight-colors, cardinal); + } + .number { + color: map-get($highlight-colors, bondi-blue); + } + .params { + color: map-get($highlight-colors, bahama-blue); + } + } + // JavaScript + &.js .code { + .built_in, + .title { + color: map-get($highlight-colors, scampi); + } + .javadoc { + color: map-get($highlight-colors, pewter); + } + .tag, + .javadoctag { + color: map-get($highlight-colors, cardinal); + } + .tag .title { + color: map-get($highlight-colors, night-rider); + } + .regexp { + color: map-get($highlight-colors, persimmon); + } + .literal, + .number { + color: map-get($highlight-colors, bondi-blue); + } + } + // JSON + &.json .code { + .attribute { + color: map-get($highlight-colors, egyptian-blue); + } + .number, + .literal { + color: map-get($highlight-colors, bondi-blue); + } + } + // Makefile + &.mak .code { + .constant { + color: map-get($highlight-colors, night-rider); + } + .title { + color: map-get($highlight-colors, scampi); + } + .keyword, + .meta-keyword { + color: map-get($highlight-colors, bondi-blue); + } + } + // Markdown + &.md .code { + .value, + .link_label, + .strong, + .emphasis, + .blockquote, + .quote, + .section { + color: map-get($highlight-colors, egyptian-blue); + } + .link_reference, + .symbol, + .code { + color: map-get($highlight-colors, bondi-blue); + } + .link_url, + .link { + text-decoration: underline; + } + } + // Nginx + &.nginx .code { + .title, + .attribute { + color: map-get($highlight-colors, cardinal); + } + .built_in, + .literal { + color: map-get($highlight-colors, bondi-blue); + } + .regexp { + color: map-get($highlight-colors, egyptian-blue); + } + .variable { + color: map-get($highlight-colors, night-rider); + } + } + // Objective-C + &.objectivec .code { + .preprocessor, + .meta { + color: map-get($highlight-colors, cardinal); + + .title { + color: map-get($highlight-colors, persimmon); + } + } + .meta-string { + color: map-get($highlight-colors, egyptian-blue); + } + .title { + color: map-get($highlight-colors, scampi); + } + .literal, + .number, + .built_in { + color: map-get($highlight-colors, bondi-blue); + } + } + // Perl + &.perl .code { + .sub { + color: map-get($highlight-colors, scampi); + } + .title { + color: map-get($highlight-colors, scampi); + } + .regexp { + color: map-get($highlight-colors, persimmon); + } + + } + // PHP + &.php .code { + .phpdoc, + .doctag { + color: map-get($highlight-colors, cardinal); + } + .regexp { + color: map-get($highlight-colors, persimmon); + } + .literal, + .number { + color: map-get($highlight-colors, bondi-blue); + } + .title { + color: map-get($highlight-colors, scampi); + } + } + // Python + &.python .code { + .decorator, + .title, + .meta { + color: map-get($highlight-colors, scampi); + } + .number { + color: map-get($highlight-colors, bondi-blue); + } + } + // Ruby + &.ruby .code { + .parent, + .title { + color: map-get($highlight-colors, scampi); + } + .prompt, + .constant, + .number, + .subst .keyword, + .symbol { + color: map-get($highlight-colors, bondi-blue); + } + } + // SQL + &.sql { + .built_in { + color: map-get($highlight-colors, cardinal); + } + .number { + color: map-get($highlight-colors, bondi-blue); + } + } + // XML, HTML + &.xml, + &.html { + .tag { + color: map-get($highlight-colors, night-rider); + } + .value { + color: map-get($highlight-colors, egyptian-blue); + } + .attribute, + .attr { + color: map-get($highlight-colors, scampi); + } + .title, + .name { + color: map-get($highlight-colors, asparagus); + } + } + // Puppet + &.puppet { + .title { + color: map-get($highlight-colors, scampi); + } + .function { + color: map-get($highlight-colors, bondi-blue); + } + .name { + color: map-get($highlight-colors, cardinal); + } + .attr { + color: map-get($highlight-colors, bondi-blue); + } + } + // LESS + &.less { + .tag, + .at_rule { + color: map-get($highlight-colors, cardinal); + } + .number, + .hexcolor, + .function, + .attribute { + color: map-get($highlight-colors, bondi-blue); + } + .built_in { + color: map-get($highlight-colors, persimmon); + } + .id, + .pseudo, + .class, + .selector-id, + .selector-class, + .selector-tag { + color: map-get($highlight-colors, scampi); + } + } + // SCSS + &.scss { + .tag, + .at_rule, + .important { + color: map-get($highlight-colors, cardinal); + } + .number, + .hexcolor, + .function, + .attribute { + color: map-get($highlight-colors, bondi-blue); + } + .variable { + color: map-get($highlight-colors, night-rider); + } + .built_in { + color: map-get($highlight-colors, persimmon); + } + .id, + .pseudo, + .class, + .preprocessor, + .selector-class, + .selector-id { + color: map-get($highlight-colors, scampi); + } + .tag, + .selector-tag { + color: map-get($highlight-colors, asparagus); + } + } + // Stylus + &.stylus { + .at_rule { + color: map-get($highlight-colors, cardinal); + } + .tag, + .selector-tag { + color: map-get($highlight-colors, asparagus); + } + .number, + .hexcolor, + .attribute, + .params { + color: map-get($highlight-colors, bondi-blue); + } + .class, + .id, + .pseudo, + .title, + .selector-id, + .selector-pseudo, + .selector-class { + color: map-get($highlight-colors, scampi); + } + } + // Go + &.go { + .typename { + color: map-get($highlight-colors, cardinal); + } + .built_in, + .constant { + color: map-get($highlight-colors, bondi-blue); + } + } + // Swift + &.swift { + .preprocessor { + color: map-get($highlight-colors, cardinal); + } + .title { + color: map-get($highlight-colors, scampi); + } + .built_in, + .number, + .type { + color: map-get($highlight-colors, bondi-blue); + } + } + // YAML + &.yml { + .line + .attr { + color: map-get($highlight-colors, asparagus); + } + .line, + .string, + .type, + .literal, + .meta { + color: map-get($highlight-colors, egyptian-blue); + } + .number { + color: map-get($highlight-colors, bondi-blue); + } + } +}
\ No newline at end of file diff --git a/src/scss/tranquilpeak.scss b/src/scss/tranquilpeak.scss new file mode 100755 index 0000000..0181f98 --- /dev/null +++ b/src/scss/tranquilpeak.scss @@ -0,0 +1,66 @@ +@import + 'utils/fonts', + 'utils/variables'; + +@import + 'utils/mixins/bottom-bar', + 'utils/mixins/button', + 'utils/mixins/category', + 'utils/mixins/form', + 'utils/mixins/header', + 'utils/mixins/main', + 'utils/mixins/opacity', + 'utils/mixins/post-header-cover', + 'utils/mixins/prefix', + 'utils/mixins/share-options-bar', + 'utils/mixins/sidebar', + 'utils/mixins/tag'; + +@import + 'base/base'; + +@import 'layouts/about', +'layouts/blog', +'layouts/bottom-bar', +'layouts/cover', +'layouts/footer', +'layouts/header', +'layouts/main', +'layouts/sidebar'; + +@import + 'components/alert', + 'components/archive', + 'components/box', + 'components/button', + 'components/caption', + 'components/code', + 'components/figure', + 'components/form', + 'components/hide', + 'components/highlight-text', + 'components/icon', + 'components/image-gallery', + 'components/link', + 'components/main-content', + 'components/markdown', + 'components/media', + 'components/modal', + 'components/pagination', + 'components/post', + 'components/post-actions', + 'components/pullquote', + 'components/post-header-cover', + 'components/postShorten', + 'components/share-options-bar', + 'components/tag', + 'components/text', + 'components/tooltip', + 'components/video'; + +@import + 'pages/search'; + +@import + 'themes/hljs-tranquilpeak', + 'themes/hljs-custom';
\ No newline at end of file diff --git a/src/scss/utils/_fonts.scss b/src/scss/utils/_fonts.scss new file mode 100755 index 0000000..9047a9e --- /dev/null +++ b/src/scss/utils/_fonts.scss @@ -0,0 +1,48 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans'), local('OpenSans'), url(https://fonts.gstatic.com/s/opensans/v10/cJZKeOuBrn4kERxqtaUH3SZ2oysoEQEeKwjgmXLRnTc.ttf) format('truetype'); +} + +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(https://fonts.gstatic.com/s/opensans/v10/k3k702ZOKiLJc3WVjuplzJS3E-kSBmtLoNJPDtbj2Pk.ttf) format('truetype'); +} + +@font-face { + font-family: 'Merriweather'; + font-style: normal; + font-weight: 300; + src: local('Merriweather Light'), local('Merriweather-Light'), url(https://fonts.gstatic.com/s/merriweather/v8/ZvcMqxEwPfh2qDWBPxn6nk7nEl83IKQRaQwpv_tz1Eg.ttf) format('truetype'); +} + +@font-face { + font-family: 'Merriweather'; + font-style: normal; + font-weight: 400; + src: local('Merriweather'), url(https://fonts.gstatic.com/s/merriweather/v8/RFda8w1V0eDZheqfcyQ4EJS3E-kSBmtLoNJPDtbj2Pk.ttf) format('truetype'); +} + +@font-face { + font-family: 'Merriweather'; + font-style: normal; + font-weight: 700; + src: local('Merriweather Bold'), local('Merriweather-Bold'), url(https://fonts.gstatic.com/s/merriweather/v8/ZvcMqxEwPfh2qDWBPxn6nv83cGrqhiQgWmjXfohD0fc.ttf) format('truetype'); +} + +@font-face { + font-family: 'Merriweather'; + font-style: italic; + font-weight: 300; + src: local('Merriweather Light Italic'), local('Merriweather-LightItalic'), url(https://fonts.gstatic.com/s/merriweather/v8/EYh7Vl4ywhowqULgRdYwIGrKw6K5wsYdxr6rUL2ZGaM.ttf) format('truetype'); +} + +@font-face { + font-family: 'Merriweather'; + font-style: italic; + font-weight: 700; + src: local('Merriweather Bold Italic'), local('Merriweather-BoldItalic'), url(https://fonts.gstatic.com/s/merriweather/v8/EYh7Vl4ywhowqULgRdYwII1kRdeHIFWYEsp6A2f99b0.ttf) format('truetype'); +}
\ No newline at end of file diff --git a/src/scss/utils/_variables.scss b/src/scss/utils/_variables.scss new file mode 100755 index 0000000..4140626 --- /dev/null +++ b/src/scss/utils/_variables.scss @@ -0,0 +1,256 @@ +// Global settings +// -------------------------------------------- + +// Font families +$open-sans: 'Open Sans'; +$open-sans-sans-serif: 'Open Sans', sans-serif; +$merriweather-serif: 'Merriweather', serif; +$menlo: Menlo; + +$font-family-base: $open-sans-sans-serif; + +$font-families: ( + // base + 'headings': $open-sans-sans-serif, + // components + 'code': $menlo, + 'caption': $merriweather-serif, + 'image-gallery': $open-sans, + 'post-header-cover': $merriweather-serif, + 'post-meta': $open-sans-sans-serif, + 'post-content': $merriweather-serif, + 'post-excerpt-link': $open-sans-sans-serif, + 'highlight': $menlo, + // layout + 'sidebar': $open-sans-sans-serif +); + +// equal to 15px +$font-size-base: 1.6rem; +$font-color-base: #5d686f; +$line-height-base: 1.9em; +$letter-spacing-base: 0.01em; + +// Reduction of font size base on small screen and down +$font-size-base-sm-screen-reduction-factor: 0.1rem; + +// Font size : (X.Xrem = XXpx, 1.0rem = 10px) +$font-size: ( + 'xxlarge': 2rem, + 'xlarge': 1.8rem, + 'large': 1.7rem, + 'base': $font-size-base, + 'medium': 1.5rem, + 'small': 1.3rem, + 'xsmall': 1rem +); + +// Colors +$colors: ( + 'success': #4dc657, + 'danger': #f5311d, + 'primary': #349ef3, + 'purple': #cf6ae0, + 'base': $font-color-base, + 'warning': #f5aa0a, + 'light': #9eabb3, + // use for tag `a` + 'link': #349ef3 +); + +// Z-indexes +// `l-` prefix for layout +// `c-` prefix for components +$z-indexes: ( + // position the cover below the whole blog + 'l-cover': -1, + 'l-main': 10, + 'c-post-header-cover': 15, + 'l-header': 20, + 'l-sidebar': 20, + 'l-about': 30, + 'c-mask': 30, + 'c-post-bottom-bar': 40, + 'c-share-options-bar': 50, + 'c-tooltip': 1000, + 'c-overlay': 1009, + 'c-modal': 1010 +); + +// Media Query Ranges +// If you want to change ranges screen size, you can do it easily by changing only `$screen-min` values +$screen-min: ( + 'xs-min': 320px, + 'sm-min': 480px, + // If you change value of `md-min`, + // you have to change value of `mediumScreenWidth` too in `source/_js/sidebar.js` + 'md-min': 768px, + 'lg-min': 1024px, + 'xlg-min': 1280px +); +$screen-max: ( + 'xs-max': map-get($screen-min, sm-min) - 1, + 'sm-max': map-get($screen-min, md-min) - 1, + 'md-max': map-get($screen-min, lg-min) - 1, + 'lg-max': map-get($screen-min, xlg-min) - 1 +); +// Merged screen-* Maps +$screen: map-merge($screen-min, $screen-max); +// Shortcuts for medias +$xsmall-and-down: "only screen and (max-width : #{map-get($screen, xs-max)})" !default; +$small-and-down: "only screen and (max-width : #{map-get($screen, sm-max)})" !default; +$small-only: "only screen and (min-width : #{map-get($screen, sm-min)}) and (max-width : #{map-get($screen, sm-max)})" !default; +$small-and-up: "only screen and (min-width : #{map-get($screen, sm-min)})" !default; +$medium-and-down: "only screen and (max-width : #{map-get($screen, md-max)})" !default; +$medium-only: "only screen and (min-width : #{map-get($screen, md-min)}) and (max-width : #{map-get($screen, md-max)})" !default; +$medium-and-up: "only screen and (min-width : #{map-get($screen, md-min)})" !default; +$large-and-down: "only screen and (max-width : #{map-get($screen, lg-max)})" !default; +$large-only: "only screen and (min-width : #{map-get($screen, lg-min)}) and (max-width : #{map-get($screen, lg-max)})" !default; +$large-and-up: "only screen and (min-width : #{map-get($screen, lg-min)})" !default; +$xlarge-and-up: "only screen and (min-width : #{map-get($screen, xlg-min)})" !default; + +// Base settings +// Files are located in `base` folder +// -------------------------------------------- + +// Headings font-size : (X.Xrem = XXpx, 1.0rem = 10px) +$headings-font-size: ( + 'h1': 2.8rem, + 'h2': 2.4rem, + 'h3': 2.0rem, + 'h4': 1.8rem, + 'h5': 1.7rem, + 'h6': 1.6rem +); +// Reduction of headings font size on small screen and down +$headings-font-size-sm-screen-reduction-factor: 0.2rem; +// Reduction of headings font size on medium screen only +$headings-font-size-md-screen-reduction-factor: 0.15rem; + +// Layout settings +// Files are located in `layout` folder +// -------------------------------------------- + +// Main +$about: ( + 'background': rgba(17, 26, 35, 0), +); + +// Header +$header:( + 'height': 55px, + 'background': #fff, + 'color': #88909a, + 'border': 1px solid #eef2f8 +); + +// Sidebar +$sidebar: ( + 'md-screen-width': 75px, + 'lg-screen-width': 250px, + 'xlg-screen-width': 500px, + 'background': rgba(17, 26, 35, 0), + 'color': #ebebeb +); + +// Main +$main: ( + 'padding-top': 15px, + 'background-color': #fff +); + +// Components settings +// Files are located in `components` folder +// -------------------------------------------- + +// Highlight code +$highlight: ( + 'background': #f7f8f8, + 'font-size': 1.4rem, + 'border': 1px solid, + 'line-height': 1.3em +); + +// Highlight colors +// name of colors: http://www.color-blindness.com +$highlight-colors: ( + // Background + 'white': #fff, + // General color + 'night-rider': #333, + 'bondi-blue': #0086b3, + 'persimmon': #df5000, + 'asparagus': #63a35c, + // Comment + 'pewter': #969896, + 'cardinal': #a71d5d, + 'scampi': #795da3, + 'bahama-blue': #1d3e81, + 'egyptian-blue': #183691, + // Deletion color for .diff file + 'free-speech-red': #bd2c00, + // Deletion background color for .diff file + 'misty-rose': #ffecec, + // Addition color for .diff file + 'limeade': #55a532, + // Addition background color for .diff file + 'honeydew': #eaffea +); +// Highlight text +$highlight-text-bg-colors: ( + 'red': lighten(red, 45%), + 'green': lighten(green, 65%), + 'blue': lighten(blue, 45%), + 'purple': lighten(purple, 70%), + 'orange': lighten(orange, 40%), + 'yellow': lighten(yellow, 40%), + 'cyan': lighten(cyan, 40%), + 'primary': lighten(map-get($colors, 'primary'), 35%), + 'success': lighten(map-get($colors, 'success'),35%), + 'warning': lighten(map-get($colors, 'warning'), 40%), + 'danger': lighten(map-get($colors, 'danger'), 40%), +); +// Image gallery photos +// Space between 2 photos +$image-gallery-photos-margin: 2px; + +// Main content +$main-content: ( + 'max-width': 750px, + 'padding-right-left': 20px, +); + +// Mardown +// These variables are use to have headings smaller than general headings title +// and use correctly headings in a post instead of use only header below h2 +// because they are larger than the post title or something like that +// font-size : (X.Xrem = XXpx, 1.0rem = 10px) +$markdown-headings-font-size: ( + 'h1': 3rem, + 'h2': 2.7rem, + 'h3': 2.4rem, + 'h4': 2.1rem, + 'h5': 1.9rem, + 'h6': 1.7rem +); +// Reduction of markdwon headings on small screen and down +$markdown-headings-font-size-sm-screen-reduction-factor: 0.35rem; +// Reduction of markdwon headings on medium screen only +$markdown-headings-font-size-md-screen-reduction-factor: 0.2rem; + +// Pagination +$pagination-height: 60px; + +// Post thumbnail image +// Width and height of post's thumbnail image +$post-thumbnail-image-width: 140px; + +// Tooltip +$tooltip: ( + 'min-width': 180px, + 'background': rgba(0, 0, 20, 0.93), + // Don't change this value, used to horizontally center the tooltip content + 'arrow-width': 15px, + // Don't change this value, used to vertically center the tooltip content + 'arrow-height': 12px +); diff --git a/src/scss/utils/mixins/_bottom-bar.scss b/src/scss/utils/mixins/_bottom-bar.scss new file mode 100755 index 0000000..32f7131 --- /dev/null +++ b/src/scss/utils/mixins/_bottom-bar.scss @@ -0,0 +1,46 @@ +/// Mixin helper to stylized bottom bar in small size +/// minus width of sidebar on extra large screen and minus its padding +@mixin bottom-bar-xs { + width: calc(100% - #{map-get($sidebar, xlg-screen-width)} - 15px * 2); + left: map-get($sidebar, xlg-screen-width); +} + +/// Mixin helper to stylized bottom bar in small size +/// minus width of sidebar on large screen and minus its padding +@mixin bottom-bar-sm { + width: calc(100% - #{map-get($sidebar, lg-screen-width)} - 15px * 2); + left: map-get($sidebar, lg-screen-width); +} + +/// Mixin helper to stylized bottom bar in medium size +/// minus width of sidebar on medium screen and minus its padding +@mixin bottom-bar-md { + width: calc(100% - #{map-get($sidebar, md-screen-width)} - 15px * 2); + left: map-get($sidebar, md-screen-width); +} + +/// Mixin helper to stylized bottom bar in large size minus its padding +@mixin bottom-bar-lg { + width: calc(100% - 15px * 2); + left: 0; +} + +/// Mixin helper to pushed bottom bar from medium sidebar size +@mixin bottom-bar-pushed-md { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, md-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} + +/// Mixin helper to pushed bottom bar from large sidebar size +@mixin bottom-bar-pushed-lg { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, lg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} +/// Mixin helper to pushed bottom bar from extra large sidebar size +@mixin bottom-bar-pushed-xlg { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, xlg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +}
\ No newline at end of file diff --git a/src/scss/utils/mixins/_button.scss b/src/scss/utils/mixins/_button.scss new file mode 100755 index 0000000..a8cd488 --- /dev/null +++ b/src/scss/utils/mixins/_button.scss @@ -0,0 +1,19 @@ +/// Helper for 'components/button' to stylize a button with a specified color +/// @param {Color} $color - Color CSS value +@mixin button-color-variant($color) { + color: $color !important; + border: 1px solid $color; + + &:hover { + color: darken($color, 15) !important; + border: 1px solid darken($color, 15); + } +} + +/// Helper for 'components/button' to stylize a button with a specified size and padding +/// @param {Number} $font-size - Font size CSS value +/// @param {List} $padding - Padding CSS value +@mixin button-size-variant($font-size, $padding) { + font-size: $font-size; + padding: $padding; +}
\ No newline at end of file diff --git a/src/scss/utils/mixins/_category.scss b/src/scss/utils/mixins/_category.scss new file mode 100755 index 0000000..79ef92e --- /dev/null +++ b/src/scss/utils/mixins/_category.scss @@ -0,0 +1,20 @@ +/// Helper for 'components/category' to stylize a category with a specified color +/// @param {Color} $color - Color CSS value +@mixin category-color-variant($color) { + color: $color !important; + border: 1px solid $color; + + &:hover { + color: darken($color, 15) !important; + border: 1px solid darken($color, 15); + text-decoration: none; + } +} + +/// Helper for 'components/category' to stylize a category with a specified size and padding +/// @param {Number} $font-size - Font-size CSS value +/// @param {List} $padding - Padding CSS value +@mixin category-size-variant($font-size, $padding) { + font-size: $font-size; + padding: $padding; +}
\ No newline at end of file diff --git a/src/scss/utils/mixins/_form.scss b/src/scss/utils/mixins/_form.scss new file mode 100755 index 0000000..a24398f --- /dev/null +++ b/src/scss/utils/mixins/_form.scss @@ -0,0 +1,13 @@ +/// Helper to stylize a input with a specified size +/// @param {Number} $height - Height CSS value +/// @param {String} $padding - Padding CSS value +/// @param {String} $font-size - Font-size CSS value +/// @param {String} $line-height - Line-height CSS value +@mixin input-size-variant($height, $padding, $font-size, $line-height) { + & { + height: $height; + padding: $padding; + font-size: $font-size; + line-height: $line-height; + } +}
\ No newline at end of file diff --git a/src/scss/utils/mixins/_header.scss b/src/scss/utils/mixins/_header.scss new file mode 100755 index 0000000..028275c --- /dev/null +++ b/src/scss/utils/mixins/_header.scss @@ -0,0 +1,19 @@ +/// Mixin helper to push header from medium sidebar size +@mixin header-pushed-md { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, md-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} + +/// Mixin helper to push header from large sidebar size +@mixin header-pushed-lg { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, lg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} +/// Mixin helper to push header from extra large sidebar size +@mixin header-pushed-xlg { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, xlg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +}
\ No newline at end of file diff --git a/src/scss/utils/mixins/_main.scss b/src/scss/utils/mixins/_main.scss new file mode 100755 index 0000000..a74364c --- /dev/null +++ b/src/scss/utils/mixins/_main.scss @@ -0,0 +1,48 @@ +/// Mixin helper to stylized `main` div in extra small size +@mixin main-xs { + padding-top: map-get($main, padding-top); + float: right; + width: calc(100% - #{map-get($sidebar, xlg-screen-width)}); +} + +/// Mixin helper to stylized `main` div in small size +@mixin main-sm { + padding-top: map-get($main, padding-top); + float: right; + width: calc(100% - #{map-get($sidebar, lg-screen-width)}); +} + +/// Mixin helper to stylized `main` div in medium size +@mixin main-md { + padding-top: map-get($main, padding-top); + float: right; + width: calc(100% - #{map-get($sidebar, md-screen-width)}); +} + +/// Mixin helper to stylized `main` div in large size +@mixin main-lg { + padding-top: map-get($header, height) + map-get($main, padding-top); + display: block; + width: 100%; +} + +/// Mixin helper to push `main` div from medium sidebar size +@mixin main-pushed-md { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, md-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} + +/// Mixin helper to push `main` div from large sidebar size +@mixin main-pushed-lg { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, lg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} + +/// Mixin helper to push `main` div from extra large sidebar size +@mixin main-pushed-xlg { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, xlg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} diff --git a/src/scss/utils/mixins/_opacity.scss b/src/scss/utils/mixins/_opacity.scss new file mode 100755 index 0000000..8788358 --- /dev/null +++ b/src/scss/utils/mixins/_opacity.scss @@ -0,0 +1,7 @@ +/// Mixin helper to add opacity rules +/// @param {number} $opacity - Opacity CSS value +@mixin opacity($opacity) { + opacity: $opacity; + $opacity-ie: $opacity * 100; + filter: alpha(opacity=$opacity-ie); // IE8 +}
\ No newline at end of file diff --git a/src/scss/utils/mixins/_post-header-cover.scss b/src/scss/utils/mixins/_post-header-cover.scss new file mode 100755 index 0000000..fd805f9 --- /dev/null +++ b/src/scss/utils/mixins/_post-header-cover.scss @@ -0,0 +1,47 @@ +/// Mixin helper to stylized post header cover in extra small size +/// minus width of sidebar on extra large screen +@mixin post-header-cover-xs { + width: calc(100% - #{map-get($sidebar, xlg-screen-width)}); + left: map-get($sidebar, xlg-screen-width); +} + +/// Mixin helper to stylized post header cover in small size +/// minus width of sidebar on large screen +@mixin post-header-cover-sm { + width: calc(100% - #{map-get($sidebar, lg-screen-width)}); + left: map-get($sidebar, lg-screen-width); +} + +/// Mixin helper to stylized post header cover in medium size +/// minus width of sidebar on medium screen +@mixin post-header-cover-md { + width: calc(100% - #{map-get($sidebar, md-screen-width)}); + left: map-get($sidebar, md-screen-width); +} + +/// Mixin helper to stylized post header cover in large size +@mixin post-header-cover-lg { + width: 100%; + left: 0; +} + +/// Mixin helper to pushed post header cover from medium sidebar size +@mixin post-header-cover-pushed-md { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, md-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} + +/// Mixin helper to pushed post header cover from large sidebar size +@mixin post-header-cover-pushed-lg { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, lg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} + +/// Mixin helper to pushed post header cover from extra large sidebar size +@mixin post-header-cover-pushed-xlg { + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, xlg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +}
\ No newline at end of file diff --git a/src/scss/utils/mixins/_prefix.scss b/src/scss/utils/mixins/_prefix.scss new file mode 100755 index 0000000..74d6f13 --- /dev/null +++ b/src/scss/utils/mixins/_prefix.scss @@ -0,0 +1,11 @@ +/// Mixin helper to output vendor prefixes +/// @param {String} $property - Unprefixed CSS property +/// @param {*} $value - Raw CSS value +/// @param {List} $prefixes - List of prefixes to output +@mixin prefix($property, $value, $prefixes: ()) { + @each $prefix in $prefixes { + -#{$prefix}-#{$property}: #{$value}; + } + + #{$property}: #{$value}; +}
\ No newline at end of file diff --git a/src/scss/utils/mixins/_share-options-bar.scss b/src/scss/utils/mixins/_share-options-bar.scss new file mode 100755 index 0000000..6450ca6 --- /dev/null +++ b/src/scss/utils/mixins/_share-options-bar.scss @@ -0,0 +1,20 @@ +/// Mixin helper to stylized `share-options-bar` div in extra small size +@mixin share-options-bar-xs { + width: calc(100% - #{map-get($sidebar, xlg-screen-width)}); + left: map-get($sidebar, xlg-screen-width); +} +/// Mixin helper to stylized `share-options-bar` div in small size +@mixin share-options-bar-sm { + width: calc(100% - #{map-get($sidebar, lg-screen-width)}); + left: map-get($sidebar, lg-screen-width); +} +/// Mixin helper to stylized `share-options-bar` div in medium size +@mixin share-options-bar-md { + width: calc(100% - #{map-get($sidebar, md-screen-width)}); + left: map-get($sidebar, md-screen-width); + +} +/// Mixin helper to stylized `share-options-bar` div in large size +@mixin share-options-bar-lg { + width: 100%; +} diff --git a/src/scss/utils/mixins/_sidebar.scss b/src/scss/utils/mixins/_sidebar.scss new file mode 100755 index 0000000..f1ff827 --- /dev/null +++ b/src/scss/utils/mixins/_sidebar.scss @@ -0,0 +1,197 @@ +/// Mixin helper to display the sidebar in medium size +@mixin sidebar-md { + width: map-get($sidebar, md-screen-width); + + // Author information + .sidebar-profile { + .sidebar-profile-picture { + width: 30px; + height: 30px; + line-height: 30px; + vertical-align: middle; + border-radius: 30px; + } + .sidebar-profile-name { + display: none; + } + } + // Buttons + ul.sidebar-buttons { + li.sidebar-button { + text-align: center; + + .sidebar-button-link { + text-align: center; + width: 100%; + + .sidebar-button-icon { + font-size: 2rem; + display: inline-block; + text-align: center; + width: 30px; + height: 30px; + line-height: 30px; + padding-top: 0; + vertical-align: middle; + } + .sidebar-button-desc { + display: none; + } + } + } + } + // Used to animate the sidebar (pushed effect) + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, md-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} + +/// Mixin helper to display the sidebar in large size +@mixin sidebar-lg { + width: map-get($sidebar, lg-screen-width); + + // Author information + .sidebar-profile { + height: 130px; + padding-top: 40px; + padding-bottom: 7.5px; + + .sidebar-profile-picture { + width: 90px; + height: 90px; + border-radius: 90px; + margin-bottom: 5px; + } + .sidebar-profile-name { + font-size: 1.6rem; + } + } + // Buttons + ul.sidebar-buttons { + li.sidebar-button { + text-align: left; + + .sidebar-button-link { + text-align: left; + width: auto; + padding-left: 23px; + padding-top: 0; + + // Font-awesome icon + .sidebar-button-icon { + font-size: 2rem; + display: inline-block; + text-align: center; + width: 30px; + height: 30px; + line-height: 30px; + padding-top: 0; + vertical-align: middle; + margin-right: 15px; + } + // Description (name) of a link + .sidebar-button-desc { + display: inline-block; + width: auto; + height: 35px; + line-height: 35px; + font-size: 1.5rem; + letter-spacing: 0.3px; + vertical-align: middle; + } + } + } + } + // Used to animate the sidebar (pushed effect) + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, lg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} + +/// Mixin helper to display the sidebar in large size +@mixin sidebar-xlg { + width: map-get($sidebar, xlg-screen-width); + box-sizing: border-box; + padding: 0 80px; + .sidebar-container { + position: relative; + top: 50%; + transform: translateY(-50%); + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + } + // Author information + .sidebar-profile { + padding-top: 0; + padding-bottom: 7.5px; + + .sidebar-profile-picture { + width: 90px; + height: 90px; + border-radius: 90px; + margin-bottom: 5px; + } + .sidebar-profile-bio, + .sidebar-profile-job, + .sidebar-profile-location { + font-weight: 400; + font-size: 1.6rem; + color: map-get($sidebar, color); + } + .sidebar-profile-job, + .sidebar-profile-location { + margin-top: 0; + width: 49%; + display: inline-block; + } + } + // Buttons + ul.sidebar-buttons { + width: 49%; + vertical-align: top; + display: inline-block; + + li.sidebar-button { + text-align: left; + box-sizing: border-box; + .sidebar-button-link { + text-align: left; + width: auto; + padding-top: 0; + white-space: nowrap; + // Font-awesome icon + .sidebar-button-icon { + font-size: 2rem; + float: left; + text-align: center; + width: 30px; + height: 35px; + line-height: 35px; + padding-top: 0; + vertical-align: middle; + margin-right: 15px; + } + // Description (name) of a link + .sidebar-button-desc { + display: block; + width: auto; + height: 35px; + line-height: 35px; + font-size: 1.5rem; + letter-spacing: 0.3px; + vertical-align: middle; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + &:nth-child(odd) { + padding-right: 20px; + } + } + } + // Used to animate the sidebar (pushed effect) + &.pushed { + @include prefix(transform, translate3d(#{map-get($sidebar, xlg-screen-width)}, 0, 0), 'webkit' 'moz'); + } +} diff --git a/src/scss/utils/mixins/_tag.scss b/src/scss/utils/mixins/_tag.scss new file mode 100755 index 0000000..b5b63b9 --- /dev/null +++ b/src/scss/utils/mixins/_tag.scss @@ -0,0 +1,20 @@ +/// Helper for 'components/tag' to stylize a tag with a specified color +/// @param {Color} $color - Color CSS value +@mixin tag-color-variant($color) { + color: $color !important; + border: 1px solid $color; + + &:hover { + color: darken($color, 15) !important; + border: 1px solid darken($color, 15); + text-decoration: none; + } +} + +/// Helper for 'components/tag' to stylize a tag with a specified size and padding +/// @param {String} $font-size - Font-size CSS value +/// @param {List} $padding - List of padding CSS value +@mixin tag-size-variant($font-size, $padding) { + font-size: $font-size; + padding: $padding; +}
\ No newline at end of file |