├── .gitignore ├── LICENSE ├── README.md ├── archetypes ├── default.md └── page.md ├── assets └── src │ ├── images │ ├── apple-touch-icon.png │ └── favicon.ico │ ├── scripts │ ├── _external │ │ ├── baguetteBox.js │ │ ├── headroom.js │ │ └── lazyload.js │ └── main.js │ └── styles │ ├── _chroma_friendly.scss │ ├── _components │ ├── base.scss │ ├── content.scss │ ├── elements.scss │ ├── footer.scss │ ├── homepage.scss │ └── navbar.scss │ ├── _external │ ├── baguetteBox.css │ ├── milligram.css │ └── normalize.css │ ├── _settings.scss │ └── styles.scss ├── exampleSite ├── config.toml └── content │ ├── _index.md │ ├── categories │ └── _index.md │ ├── media │ ├── _index.md │ ├── image-1.jpg │ └── video.mp4 │ ├── photos.md │ ├── posts │ ├── 2014 │ │ ├── creating-a-new-theme.md │ │ ├── goisforlovers.md │ │ ├── hugoisforlovers.md │ │ └── migrate-from-jekyll.md │ ├── 2016 │ │ └── lorem-ipsum.md │ ├── 2017 │ │ ├── code.md │ │ ├── gist.md │ │ ├── images.md │ │ ├── instagram.md │ │ ├── speakerdeck.md │ │ ├── tables.md │ │ ├── twitter.md │ │ ├── typography.md │ │ ├── video.md │ │ ├── vimeo.md │ │ └── youtube.md │ ├── 2019 │ │ └── numbered_list.md │ └── _index.md │ ├── projects.md │ └── tags │ └── _index.md ├── i18n ├── en.toml └── pl.toml ├── images ├── screenshot.png └── tn.png ├── layouts ├── 404.html ├── _default │ ├── baseof.html │ ├── list.html │ ├── rss.xml │ ├── single.html │ ├── taxonomy.html │ └── terms.html ├── index.html ├── page │ └── single.html ├── partials │ ├── footer.html │ ├── head.html │ ├── navbar.html │ └── posts_list.html ├── shortcodes │ ├── adsense.html │ ├── image.html │ ├── speakerdeck.html │ ├── video.html │ ├── vimeo.html │ └── youtube.html └── sitemap.xml ├── resources └── _gen │ ├── assets │ ├── css │ │ └── assets │ │ │ └── css │ │ │ ├── external.css_d3f53f09220d597dac26fe7840c31fc9.content │ │ │ └── external.css_d3f53f09220d597dac26fe7840c31fc9.json │ ├── js │ │ └── assets │ │ │ └── js │ │ │ ├── scripts.js_d3f53f09220d597dac26fe7840c31fc9.content │ │ │ └── scripts.js_d3f53f09220d597dac26fe7840c31fc9.json │ └── scss │ │ └── src │ │ └── styles │ │ ├── styles.scss_6e769e1f8b8c9ae08c3b967a8651114c.content │ │ └── styles.scss_6e769e1f8b8c9ae08c3b967a8651114c.json │ └── images │ └── media │ ├── image-1_hu3d03a01dcc18bc5be0e67db3d8d209a6_1073788_320x0_resize_q75_box.jpg │ ├── image-1_hu3d03a01dcc18bc5be0e67db3d8d209a6_1073788_480x0_resize_q75_box.jpg │ └── image-1_hu3d03a01dcc18bc5be0e67db3d8d209a6_1073788_768x0_resize_q75_box.jpg └── theme.toml /.gitignore: -------------------------------------------------------------------------------- 1 | assets/node_modules 2 | exampleSite/public 3 | exampleSite/resources 4 | exampleSite/themes 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Przemysław Kołodziejczyk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simplicity 2 | 3 | Very simple, clean and readable (I think so) Hugo theme. 4 | 5 | #### Responsive design 6 | It works on mobile, tablet and desktop. 7 | #### Responsive images 8 | It generates several image sizes during the build process and displays the best one for given device/resolution. 9 | #### Lazy loading images 10 | This theme uses [LazyLoad](https://github.com/verlok/lazyload) to speed up your web application by loading images as they enter the viewport. 11 | #### Clean typography 12 | It should be a pleasure to read your blog, right? 13 | #### Additional shortcodes 14 | Shortcodes for Google Adsense, images, Speaker Deck, Video, Vimeo, Youtube. 15 | #### Google Adsense 16 | You can use the shortcode to insert Adsense Ad wherever you want. 17 | #### Google Analytics 18 | Just add a Google Analytics code to turn it on. 19 | #### Lightbox 20 | Image shortcode allows to turn on [baguetteBox.js](https://feimosi.github.io/baguetteBox.js/) for given image. 21 | #### Syntax highlighting. 22 | Built-in Chroma Native color theme. 23 | #### Auto-hide/show header 24 | This theme uses [headroom.js](http://wicky.nillia.ms/headroom.js/) script. 25 | #### Page scroll indicator 26 | Displays progress bar on the top of the page when user scrolls the page. 27 | #### Disqus 28 | Just add a Disqus shortname to enable comments. 29 | #### Categories 30 | A separate page with a list of all categories and list of posts for a selected category. 31 | #### Tags 32 | A separate page with a list of all categories and list of posts for a selected tag. 33 | #### RSS 34 | Custom RSS template without an e-mail address. 35 | #### Sitemap 36 | Custom sitemap template to prevent rendering content from media directory. 37 | #### Social icons 38 | Add information about your social profile in the config file to display it on the homepage. Supported services: email, Facebook, Github, Google+, LinkedIn, Messenger, Spotify, Stackoverflow, Telegram, Twitter. 39 | #### Gravatar support 40 | Just add your Gravatar email to the config file to display your avatar on the home page. 41 | #### and more 42 | - OpenGraph support 43 | - Schema Structured Data 44 | - Twitter card 45 | - Display license in footer 46 | - No JS frameworks, no CSS frameworks, no jQuery 47 | 48 | # Demo 49 | 50 | You can preview this theme on my blogs - [eshlox.net](https://eshlox.net) or [eshlox.pl](https://eshlox.pl). 51 | 52 | ## Table of Contents 53 | 54 | - [Table of Contents](#table-of-contents) 55 | - [Getting Started](#getting-started) 56 | - [exampleSite](#examplesite) 57 | - [config.toml](#configtoml) 58 | - [favicons](#favicons) 59 | - [Shortcodes](#shortcodes) 60 | - [figure](#figure) 61 | - [Development](#development) 62 | - [Browsers support](#browsers-support) 63 | - [License](#license) 64 | 65 | ## Getting Started 66 | 67 | Run the following commands in your Hugo site directory to download the theme: 68 | 69 | ``` 70 | mkdir themes 71 | cd themes 72 | git clone https://github.com/eshlox/simplicity.git 73 | ``` 74 | 75 | ### exampleSite 76 | 77 | Look inside `exampleSite` directory to find out how to configure your site. 78 | 79 | That's how the structure looks like: 80 | 81 | ``` 82 | exampleSite/ 83 | ├── config.toml 84 | ├── content 85 | │   ├── _index.md 86 | │   ├── categories 87 | │   │   └── _index.md 88 | │   ├── media 89 | │   │   ├── _index.md 90 | │   │   ├── image-1.jpg 91 | │   │   └── video.mp4 92 | │   ├── photos.md 93 | │   ├── posts 94 | │   │   ├── 2014 95 | │   │   │   ├── creating-a-new-theme.md 96 | │   │   │   ├── goisforlovers.md 97 | │   │   │   ├── hugoisforlovers.md 98 | │   │   │   └── migrate-from-jekyll.md 99 | │   │   ├── 2016 100 | │   │   │   └── lorem-ipsum.md 101 | │   │   ├── 2017 102 | │   │   │   ├── images.md 103 | │   │   │   └── typography.md 104 | │   │   └── _index.md 105 | │   ├── projects.md 106 | │   └── tags 107 | │   └── _index.md 108 | └── resources 109 | └── _gen 110 | └── images 111 | └── media 112 | ├── image-1_hu3d03a01dcc18bc5be0e67db3d8d209a6_1073788_320x0_resize_q75_box.jpg 113 | ├── image-1_hu3d03a01dcc18bc5be0e67db3d8d209a6_1073788_480x0_resize_q75_box.jpg 114 | └── image-1_hu3d03a01dcc18bc5be0e67db3d8d209a6_1073788_768x0_resize_q75_box.jpg 115 | ``` 116 | 117 | Every `_index.md` file contains a title, language and slug. 118 | 119 | ### config.toml 120 | 121 | Copy `config.toml` from `exampleSite` to the root directory of your Hugo site and modify it according to your needs. 122 | 123 | ### favicons 124 | 125 | This theme contains default favicon with `S` letter. If you want to change it, create a directory `assets/src/images` inside the root of your Hugo site and put your favicon files there. They should have names: `favicon.ico` and `apple-touch-icon.png`. 126 | 127 | ## Shortcodes 128 | 129 | This theme includes additional shortcodes. 130 | 131 | ### Adsense 132 | 133 | Add Adsense configuration and use `{{< adsense >}}` in your post to display an ad. 134 | 135 | ### Image 136 | 137 | All images should be stored in `content/images` directory. Each subdirectory should contain `_index.md` file with this content: 138 | 139 | ``` 140 | --- 141 | title: Media Folder 142 | --- 143 | 144 | ``` 145 | 146 | Insert responsive image with title: 147 | 148 | `{{< image src="media/image-1.jpg" title="Photo by Ales Krivec on Unsplash" >}}` 149 | 150 | Full page width image: 151 | 152 | `{{< image src="media/image-1.jpg" title="Photo by Ales Krivec on Unsplash" full="true">}}` 153 | 154 | Lightbox: 155 | 156 | `{{< image src="media/image-1.jpg" lightbox="true" >}}` 157 | 158 | Rounded corners: 159 | 160 | `{{< image src="media/image-1.jpg" round="50" >}}` 161 | 162 | Insert image without resizing (the same image for all devices/resolutions). 163 | 164 | `{{< image src="media/image-1.jpg" resize="false" >}}` 165 | 166 | ### Speaker Deck 167 | 168 | `{{< speakerdeck 50021f75cf1db900020005e7 >}}` 169 | 170 | ### Video 171 | 172 | `{{< video src="media/video.mp4" >}}` 173 | 174 | ### Responsive Vimeo 175 | 176 | `{{< vimeo 265143954 >}}` 177 | 178 | ### Responsive Youtube 179 | 180 | `{{< vimeo 265143954 >}}` 181 | 182 | ## Development 183 | 184 | 1. Install dependencies. 185 | 186 | ```cd assets && yarn install``` 187 | 188 | 2. Run development server. 189 | 190 | ```hugo server --source=exampleSite --themesDir=../..``` 191 | 192 | ## Browsers support 193 | 194 | Dekstop: 195 | 196 | - Firefox (latest) 197 | - Chrome (latest) 198 | - Safari (latest) 199 | 200 | Mobile: 201 | 202 | - Firefox (latest) 203 | - Chrome (latest) 204 | - Safari (latest) 205 | 206 | It probably works in other browsers but it hasn't been tested yet. 207 | 208 | ## Licence 209 | 210 | This theme is released under the MIT license. Please read the [license](https://github.com/eshlox/simplicity/blob/master/LICENSE) for more information. 211 | -------------------------------------------------------------------------------- /archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .TranslationBaseName "-" " " | title }}" 3 | date: {{ .Date }} 4 | categories: [] 5 | tags: [] 6 | language: en 7 | slug: 8 | draft: true 9 | --- 10 | -------------------------------------------------------------------------------- /archetypes/page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .TranslationBaseName "-" " " | title }}" 3 | language: en 4 | slug: 5 | draft: true 6 | --- 7 | -------------------------------------------------------------------------------- /assets/src/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eshlox/simplicity/8696b3b61946d89bb0cd1fc1920940544f1758e9/assets/src/images/apple-touch-icon.png -------------------------------------------------------------------------------- /assets/src/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eshlox/simplicity/8696b3b61946d89bb0cd1fc1920940544f1758e9/assets/src/images/favicon.ico -------------------------------------------------------------------------------- /assets/src/scripts/_external/baguetteBox.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * baguetteBox.js 3 | * @author feimosi 4 | * @version 1.11.0 5 | * @url https://github.com/feimosi/baguetteBox.js 6 | */ 7 | 8 | /* global define, module */ 9 | 10 | (function (root, factory) { 11 | 'use strict'; 12 | if (typeof define === 'function' && define.amd) { 13 | define(factory); 14 | } else if (typeof exports === 'object') { 15 | module.exports = factory(); 16 | } else { 17 | root.baguetteBox = factory(); 18 | } 19 | }(this, function () { 20 | 'use strict'; 21 | 22 | // SVG shapes used on the buttons 23 | var leftArrow = '' + 24 | '' + 26 | '', 27 | rightArrow = '' + 28 | '' + 30 | '', 31 | closeX = '' + 32 | '' + 33 | '' + 34 | '' + 35 | ''; 36 | // Global options and their defaults 37 | var options = {}, 38 | defaults = { 39 | captions: true, 40 | buttons: 'auto', 41 | fullScreen: false, 42 | noScrollbars: false, 43 | bodyClass: 'baguetteBox-open', 44 | titleTag: false, 45 | async: false, 46 | preload: 2, 47 | animation: 'slideIn', 48 | afterShow: null, 49 | afterHide: null, 50 | onChange: null, 51 | overlayBackgroundColor: 'rgba(0,0,0,.8)' 52 | }; 53 | // Object containing information about features compatibility 54 | var supports = {}; 55 | // DOM Elements references 56 | var overlay, slider, previousButton, nextButton, closeButton; 57 | // An array with all images in the current gallery 58 | var currentGallery = []; 59 | // Current image index inside the slider 60 | var currentIndex = 0; 61 | // Visibility of the overlay 62 | var isOverlayVisible = false; 63 | // Touch event start position (for slide gesture) 64 | var touch = {}; 65 | // If set to true ignore touch events because animation was already fired 66 | var touchFlag = false; 67 | // Regex pattern to match image files 68 | var regex = /.+\.(gif|jpe?g|png|webp)/i; 69 | // Object of all used galleries 70 | var data = {}; 71 | // Array containing temporary images DOM elements 72 | var imagesElements = []; 73 | // The last focused element before opening the overlay 74 | var documentLastFocus = null; 75 | var overlayClickHandler = function(event) { 76 | // Close the overlay when user clicks directly on the background 77 | if (event.target.id.indexOf('baguette-img') !== -1) { 78 | hideOverlay(); 79 | } 80 | }; 81 | var previousButtonClickHandler = function(event) { 82 | event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true; // eslint-disable-line no-unused-expressions 83 | showPreviousImage(); 84 | }; 85 | var nextButtonClickHandler = function(event) { 86 | event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true; // eslint-disable-line no-unused-expressions 87 | showNextImage(); 88 | }; 89 | var closeButtonClickHandler = function(event) { 90 | event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true; // eslint-disable-line no-unused-expressions 91 | hideOverlay(); 92 | }; 93 | var touchstartHandler = function(event) { 94 | touch.count++; 95 | if (touch.count > 1) { 96 | touch.multitouch = true; 97 | } 98 | // Save x and y axis position 99 | touch.startX = event.changedTouches[0].pageX; 100 | touch.startY = event.changedTouches[0].pageY; 101 | }; 102 | var touchmoveHandler = function(event) { 103 | // If action was already triggered or multitouch return 104 | if (touchFlag || touch.multitouch) { 105 | return; 106 | } 107 | event.preventDefault ? event.preventDefault() : event.returnValue = false; // eslint-disable-line no-unused-expressions 108 | var touchEvent = event.touches[0] || event.changedTouches[0]; 109 | // Move at least 40 pixels to trigger the action 110 | if (touchEvent.pageX - touch.startX > 40) { 111 | touchFlag = true; 112 | showPreviousImage(); 113 | } else if (touchEvent.pageX - touch.startX < -40) { 114 | touchFlag = true; 115 | showNextImage(); 116 | // Move 100 pixels up to close the overlay 117 | } else if (touch.startY - touchEvent.pageY > 100) { 118 | hideOverlay(); 119 | } 120 | }; 121 | var touchendHandler = function() { 122 | touch.count--; 123 | if (touch.count <= 0) { 124 | touch.multitouch = false; 125 | } 126 | touchFlag = false; 127 | }; 128 | var contextmenuHandler = function() { 129 | touchendHandler(); 130 | }; 131 | 132 | var trapFocusInsideOverlay = function(event) { 133 | if (overlay.style.display === 'block' && (overlay.contains && !overlay.contains(event.target))) { 134 | event.stopPropagation(); 135 | initFocus(); 136 | } 137 | }; 138 | 139 | // forEach polyfill for IE8 140 | // http://stackoverflow.com/a/14827443/1077846 141 | /* eslint-disable */ 142 | if (![].forEach) { 143 | Array.prototype.forEach = function(callback, thisArg) { 144 | for (var i = 0; i < this.length; i++) { 145 | callback.call(thisArg, this[i], i, this); 146 | } 147 | }; 148 | } 149 | 150 | // filter polyfill for IE8 151 | // https://gist.github.com/eliperelman/1031656 152 | if (![].filter) { 153 | Array.prototype.filter = function(a, b, c, d, e) { 154 | c = this; 155 | d = []; 156 | for (e = 0; e < c.length; e++) 157 | a.call(b, c[e], e, c) && d.push(c[e]); 158 | return d; 159 | }; 160 | } 161 | /* eslint-enable */ 162 | 163 | // Script entry point 164 | function run(selector, userOptions) { 165 | // Fill supports object 166 | supports.transforms = testTransformsSupport(); 167 | supports.svg = testSvgSupport(); 168 | supports.passiveEvents = testPassiveEventsSupport(); 169 | 170 | buildOverlay(); 171 | removeFromCache(selector); 172 | return bindImageClickListeners(selector, userOptions); 173 | } 174 | 175 | function bindImageClickListeners(selector, userOptions) { 176 | // For each gallery bind a click event to every image inside it 177 | var galleryNodeList = document.querySelectorAll(selector); 178 | var selectorData = { 179 | galleries: [], 180 | nodeList: galleryNodeList 181 | }; 182 | data[selector] = selectorData; 183 | 184 | [].forEach.call(galleryNodeList, function(galleryElement) { 185 | if (userOptions && userOptions.filter) { 186 | regex = userOptions.filter; 187 | } 188 | 189 | // Get nodes from gallery elements or single-element galleries 190 | var tagsNodeList = []; 191 | if (galleryElement.tagName === 'A') { 192 | tagsNodeList = [galleryElement]; 193 | } else { 194 | tagsNodeList = galleryElement.getElementsByTagName('a'); 195 | } 196 | 197 | // Filter 'a' elements from those not linking to images 198 | tagsNodeList = [].filter.call(tagsNodeList, function(element) { 199 | if (element.className.indexOf(userOptions && userOptions.ignoreClass) === -1) { 200 | return regex.test(element.href); 201 | } 202 | }); 203 | if (tagsNodeList.length === 0) { 204 | return; 205 | } 206 | 207 | var gallery = []; 208 | [].forEach.call(tagsNodeList, function(imageElement, imageIndex) { 209 | var imageElementClickHandler = function(event) { 210 | event.preventDefault ? event.preventDefault() : event.returnValue = false; // eslint-disable-line no-unused-expressions 211 | prepareOverlay(gallery, userOptions); 212 | showOverlay(imageIndex); 213 | }; 214 | var imageItem = { 215 | eventHandler: imageElementClickHandler, 216 | imageElement: imageElement 217 | }; 218 | bind(imageElement, 'click', imageElementClickHandler); 219 | gallery.push(imageItem); 220 | }); 221 | selectorData.galleries.push(gallery); 222 | }); 223 | 224 | return selectorData.galleries; 225 | } 226 | 227 | function clearCachedData() { 228 | for (var selector in data) { 229 | if (data.hasOwnProperty(selector)) { 230 | removeFromCache(selector); 231 | } 232 | } 233 | } 234 | 235 | function removeFromCache(selector) { 236 | if (!data.hasOwnProperty(selector)) { 237 | return; 238 | } 239 | var galleries = data[selector].galleries; 240 | [].forEach.call(galleries, function(gallery) { 241 | [].forEach.call(gallery, function(imageItem) { 242 | unbind(imageItem.imageElement, 'click', imageItem.eventHandler); 243 | }); 244 | 245 | if (currentGallery === gallery) { 246 | currentGallery = []; 247 | } 248 | }); 249 | 250 | delete data[selector]; 251 | } 252 | 253 | function buildOverlay() { 254 | overlay = getByID('baguetteBox-overlay'); 255 | // Check if the overlay already exists 256 | if (overlay) { 257 | slider = getByID('baguetteBox-slider'); 258 | previousButton = getByID('previous-button'); 259 | nextButton = getByID('next-button'); 260 | closeButton = getByID('close-button'); 261 | return; 262 | } 263 | // Create overlay element 264 | overlay = create('div'); 265 | overlay.setAttribute('role', 'dialog'); 266 | overlay.id = 'baguetteBox-overlay'; 267 | document.getElementsByTagName('body')[0].appendChild(overlay); 268 | // Create gallery slider element 269 | slider = create('div'); 270 | slider.id = 'baguetteBox-slider'; 271 | overlay.appendChild(slider); 272 | // Create all necessary buttons 273 | previousButton = create('button'); 274 | previousButton.setAttribute('type', 'button'); 275 | previousButton.id = 'previous-button'; 276 | previousButton.setAttribute('aria-label', 'Previous'); 277 | previousButton.innerHTML = supports.svg ? leftArrow : '<'; 278 | overlay.appendChild(previousButton); 279 | 280 | nextButton = create('button'); 281 | nextButton.setAttribute('type', 'button'); 282 | nextButton.id = 'next-button'; 283 | nextButton.setAttribute('aria-label', 'Next'); 284 | nextButton.innerHTML = supports.svg ? rightArrow : '>'; 285 | overlay.appendChild(nextButton); 286 | 287 | closeButton = create('button'); 288 | closeButton.setAttribute('type', 'button'); 289 | closeButton.id = 'close-button'; 290 | closeButton.setAttribute('aria-label', 'Close'); 291 | closeButton.innerHTML = supports.svg ? closeX : '×'; 292 | overlay.appendChild(closeButton); 293 | 294 | previousButton.className = nextButton.className = closeButton.className = 'baguetteBox-button'; 295 | 296 | bindEvents(); 297 | } 298 | 299 | function keyDownHandler(event) { 300 | switch (event.keyCode) { 301 | case 37: // Left arrow 302 | showPreviousImage(); 303 | break; 304 | case 39: // Right arrow 305 | showNextImage(); 306 | break; 307 | case 27: // Esc 308 | hideOverlay(); 309 | break; 310 | case 36: // Home 311 | showFirstImage(event); 312 | break; 313 | case 35: // End 314 | showLastImage(event); 315 | break; 316 | } 317 | } 318 | 319 | function bindEvents() { 320 | var options = supports.passiveEvents ? { passive: true } : null; 321 | bind(overlay, 'click', overlayClickHandler); 322 | bind(previousButton, 'click', previousButtonClickHandler); 323 | bind(nextButton, 'click', nextButtonClickHandler); 324 | bind(closeButton, 'click', closeButtonClickHandler); 325 | bind(slider, 'contextmenu', contextmenuHandler); 326 | bind(overlay, 'touchstart', touchstartHandler, options); 327 | bind(overlay, 'touchmove', touchmoveHandler, options); 328 | bind(overlay, 'touchend', touchendHandler); 329 | bind(document, 'focus', trapFocusInsideOverlay, true); 330 | } 331 | 332 | function unbindEvents() { 333 | var options = supports.passiveEvents ? { passive: true } : null; 334 | unbind(overlay, 'click', overlayClickHandler); 335 | unbind(previousButton, 'click', previousButtonClickHandler); 336 | unbind(nextButton, 'click', nextButtonClickHandler); 337 | unbind(closeButton, 'click', closeButtonClickHandler); 338 | unbind(slider, 'contextmenu', contextmenuHandler); 339 | unbind(overlay, 'touchstart', touchstartHandler, options); 340 | unbind(overlay, 'touchmove', touchmoveHandler, options); 341 | unbind(overlay, 'touchend', touchendHandler); 342 | unbind(document, 'focus', trapFocusInsideOverlay, true); 343 | } 344 | 345 | function prepareOverlay(gallery, userOptions) { 346 | // If the same gallery is being opened prevent from loading it once again 347 | if (currentGallery === gallery) { 348 | return; 349 | } 350 | currentGallery = gallery; 351 | // Update gallery specific options 352 | setOptions(userOptions); 353 | // Empty slider of previous contents (more effective than .innerHTML = "") 354 | while (slider.firstChild) { 355 | slider.removeChild(slider.firstChild); 356 | } 357 | imagesElements.length = 0; 358 | 359 | var imagesFiguresIds = []; 360 | var imagesCaptionsIds = []; 361 | // Prepare and append images containers and populate figure and captions IDs arrays 362 | for (var i = 0, fullImage; i < gallery.length; i++) { 363 | fullImage = create('div'); 364 | fullImage.className = 'full-image'; 365 | fullImage.id = 'baguette-img-' + i; 366 | imagesElements.push(fullImage); 367 | 368 | imagesFiguresIds.push('baguetteBox-figure-' + i); 369 | imagesCaptionsIds.push('baguetteBox-figcaption-' + i); 370 | slider.appendChild(imagesElements[i]); 371 | } 372 | overlay.setAttribute('aria-labelledby', imagesFiguresIds.join(' ')); 373 | overlay.setAttribute('aria-describedby', imagesCaptionsIds.join(' ')); 374 | } 375 | 376 | function setOptions(newOptions) { 377 | if (!newOptions) { 378 | newOptions = {}; 379 | } 380 | // Fill options object 381 | for (var item in defaults) { 382 | options[item] = defaults[item]; 383 | if (typeof newOptions[item] !== 'undefined') { 384 | options[item] = newOptions[item]; 385 | } 386 | } 387 | /* Apply new options */ 388 | // Change transition for proper animation 389 | slider.style.transition = slider.style.webkitTransition = (options.animation === 'fadeIn' ? 'opacity .4s ease' : 390 | options.animation === 'slideIn' ? '' : 'none'); 391 | // Hide buttons if necessary 392 | if (options.buttons === 'auto' && ('ontouchstart' in window || currentGallery.length === 1)) { 393 | options.buttons = false; 394 | } 395 | // Set buttons style to hide or display them 396 | previousButton.style.display = nextButton.style.display = (options.buttons ? '' : 'none'); 397 | // Set overlay color 398 | try { 399 | overlay.style.backgroundColor = options.overlayBackgroundColor; 400 | } catch (e) { 401 | // Silence the error and continue 402 | } 403 | } 404 | 405 | function showOverlay(chosenImageIndex) { 406 | if (options.noScrollbars) { 407 | document.documentElement.style.overflowY = 'hidden'; 408 | document.body.style.overflowY = 'scroll'; 409 | } 410 | if (overlay.style.display === 'block') { 411 | return; 412 | } 413 | 414 | bind(document, 'keydown', keyDownHandler); 415 | currentIndex = chosenImageIndex; 416 | touch = { 417 | count: 0, 418 | startX: null, 419 | startY: null 420 | }; 421 | loadImage(currentIndex, function() { 422 | preloadNext(currentIndex); 423 | preloadPrev(currentIndex); 424 | }); 425 | 426 | updateOffset(); 427 | overlay.style.display = 'block'; 428 | if (options.fullScreen) { 429 | enterFullScreen(); 430 | } 431 | // Fade in overlay 432 | setTimeout(function() { 433 | overlay.className = 'visible'; 434 | if (options.bodyClass && document.body.classList) { 435 | document.body.classList.add(options.bodyClass); 436 | } 437 | if (options.afterShow) { 438 | options.afterShow(); 439 | } 440 | }, 50); 441 | if (options.onChange) { 442 | options.onChange(currentIndex, imagesElements.length); 443 | } 444 | documentLastFocus = document.activeElement; 445 | initFocus(); 446 | isOverlayVisible = true; 447 | } 448 | 449 | function initFocus() { 450 | if (options.buttons) { 451 | previousButton.focus(); 452 | } else { 453 | closeButton.focus(); 454 | } 455 | } 456 | 457 | function enterFullScreen() { 458 | if (overlay.requestFullscreen) { 459 | overlay.requestFullscreen(); 460 | } else if (overlay.webkitRequestFullscreen) { 461 | overlay.webkitRequestFullscreen(); 462 | } else if (overlay.mozRequestFullScreen) { 463 | overlay.mozRequestFullScreen(); 464 | } 465 | } 466 | 467 | function exitFullscreen() { 468 | if (document.exitFullscreen) { 469 | document.exitFullscreen(); 470 | } else if (document.mozCancelFullScreen) { 471 | document.mozCancelFullScreen(); 472 | } else if (document.webkitExitFullscreen) { 473 | document.webkitExitFullscreen(); 474 | } 475 | } 476 | 477 | function hideOverlay() { 478 | if (options.noScrollbars) { 479 | document.documentElement.style.overflowY = 'auto'; 480 | document.body.style.overflowY = 'auto'; 481 | } 482 | if (overlay.style.display === 'none') { 483 | return; 484 | } 485 | 486 | unbind(document, 'keydown', keyDownHandler); 487 | // Fade out and hide the overlay 488 | overlay.className = ''; 489 | setTimeout(function() { 490 | overlay.style.display = 'none'; 491 | if (document.fullscreen) { 492 | exitFullscreen(); 493 | } 494 | if (options.bodyClass && document.body.classList) { 495 | document.body.classList.remove(options.bodyClass); 496 | } 497 | if (options.afterHide) { 498 | options.afterHide(); 499 | } 500 | documentLastFocus && documentLastFocus.focus(); 501 | isOverlayVisible = false; 502 | }, 500); 503 | } 504 | 505 | function loadImage(index, callback) { 506 | var imageContainer = imagesElements[index]; 507 | var galleryItem = currentGallery[index]; 508 | 509 | // Return if the index exceeds prepared images in the overlay 510 | // or if the current gallery has been changed / closed 511 | if (typeof imageContainer === 'undefined' || typeof galleryItem === 'undefined') { 512 | return; 513 | } 514 | 515 | // If image is already loaded run callback and return 516 | if (imageContainer.getElementsByTagName('img')[0]) { 517 | if (callback) { 518 | callback(); 519 | } 520 | return; 521 | } 522 | 523 | // Get element reference, optional caption and source path 524 | var imageElement = galleryItem.imageElement; 525 | var thumbnailElement = imageElement.getElementsByTagName('img')[0]; 526 | var imageCaption = typeof options.captions === 'function' ? 527 | options.captions.call(currentGallery, imageElement) : 528 | imageElement.getAttribute('data-caption') || imageElement.title; 529 | var imageSrc = getImageSrc(imageElement); 530 | 531 | // Prepare figure element 532 | var figure = create('figure'); 533 | figure.id = 'baguetteBox-figure-' + index; 534 | figure.innerHTML = '
' + 535 | '
' + 536 | '
' + 537 | '
'; 538 | // Insert caption if available 539 | if (options.captions && imageCaption) { 540 | var figcaption = create('figcaption'); 541 | figcaption.id = 'baguetteBox-figcaption-' + index; 542 | figcaption.innerHTML = imageCaption; 543 | figure.appendChild(figcaption); 544 | } 545 | imageContainer.appendChild(figure); 546 | 547 | // Prepare gallery img element 548 | var image = create('img'); 549 | image.onload = function() { 550 | // Remove loader element 551 | var spinner = document.querySelector('#baguette-img-' + index + ' .baguetteBox-spinner'); 552 | figure.removeChild(spinner); 553 | if (!options.async && callback) { 554 | callback(); 555 | } 556 | }; 557 | image.setAttribute('src', imageSrc); 558 | image.alt = thumbnailElement ? thumbnailElement.alt || '' : ''; 559 | if (options.titleTag && imageCaption) { 560 | image.title = imageCaption; 561 | } 562 | figure.appendChild(image); 563 | 564 | // Run callback 565 | if (options.async && callback) { 566 | callback(); 567 | } 568 | } 569 | 570 | // Get image source location, mostly used for responsive images 571 | function getImageSrc(image) { 572 | // Set default image path from href 573 | var result = image.href; 574 | // If dataset is supported find the most suitable image 575 | if (image.dataset) { 576 | var srcs = []; 577 | // Get all possible image versions depending on the resolution 578 | for (var item in image.dataset) { 579 | if (item.substring(0, 3) === 'at-' && !isNaN(item.substring(3))) { 580 | srcs[item.replace('at-', '')] = image.dataset[item]; 581 | } 582 | } 583 | // Sort resolutions ascending 584 | var keys = Object.keys(srcs).sort(function(a, b) { 585 | return parseInt(a, 10) < parseInt(b, 10) ? -1 : 1; 586 | }); 587 | // Get real screen resolution 588 | var width = window.innerWidth * window.devicePixelRatio; 589 | // Find the first image bigger than or equal to the current width 590 | var i = 0; 591 | while (i < keys.length - 1 && keys[i] < width) { 592 | i++; 593 | } 594 | result = srcs[keys[i]] || result; 595 | } 596 | return result; 597 | } 598 | 599 | // Return false at the right end of the gallery 600 | function showNextImage() { 601 | return show(currentIndex + 1); 602 | } 603 | 604 | // Return false at the left end of the gallery 605 | function showPreviousImage() { 606 | return show(currentIndex - 1); 607 | } 608 | 609 | // Return false at the left end of the gallery 610 | function showFirstImage(event) { 611 | if (event) { 612 | event.preventDefault(); 613 | } 614 | return show(0); 615 | } 616 | 617 | // Return false at the right end of the gallery 618 | function showLastImage(event) { 619 | if (event) { 620 | event.preventDefault(); 621 | } 622 | return show(currentGallery.length - 1); 623 | } 624 | 625 | /** 626 | * Move the gallery to a specific index 627 | * @param `index` {number} - the position of the image 628 | * @param `gallery` {array} - gallery which should be opened, if omitted assumes the currently opened one 629 | * @return {boolean} - true on success or false if the index is invalid 630 | */ 631 | function show(index, gallery) { 632 | if (!isOverlayVisible && index >= 0 && index < gallery.length) { 633 | prepareOverlay(gallery, options); 634 | showOverlay(index); 635 | return true; 636 | } 637 | if (index < 0) { 638 | if (options.animation) { 639 | bounceAnimation('left'); 640 | } 641 | return false; 642 | } 643 | if (index >= imagesElements.length) { 644 | if (options.animation) { 645 | bounceAnimation('right'); 646 | } 647 | return false; 648 | } 649 | 650 | currentIndex = index; 651 | loadImage(currentIndex, function() { 652 | preloadNext(currentIndex); 653 | preloadPrev(currentIndex); 654 | }); 655 | updateOffset(); 656 | 657 | if (options.onChange) { 658 | options.onChange(currentIndex, imagesElements.length); 659 | } 660 | 661 | return true; 662 | } 663 | 664 | /** 665 | * Triggers the bounce animation 666 | * @param {('left'|'right')} direction - Direction of the movement 667 | */ 668 | function bounceAnimation(direction) { 669 | slider.className = 'bounce-from-' + direction; 670 | setTimeout(function() { 671 | slider.className = ''; 672 | }, 400); 673 | } 674 | 675 | function updateOffset() { 676 | var offset = -currentIndex * 100 + '%'; 677 | if (options.animation === 'fadeIn') { 678 | slider.style.opacity = 0; 679 | setTimeout(function() { 680 | supports.transforms ? 681 | slider.style.transform = slider.style.webkitTransform = 'translate3d(' + offset + ',0,0)' 682 | : slider.style.left = offset; 683 | slider.style.opacity = 1; 684 | }, 400); 685 | } else { 686 | supports.transforms ? 687 | slider.style.transform = slider.style.webkitTransform = 'translate3d(' + offset + ',0,0)' 688 | : slider.style.left = offset; 689 | } 690 | } 691 | 692 | // CSS 3D Transforms test 693 | function testTransformsSupport() { 694 | var div = create('div'); 695 | return typeof div.style.perspective !== 'undefined' || typeof div.style.webkitPerspective !== 'undefined'; 696 | } 697 | 698 | // Inline SVG test 699 | function testSvgSupport() { 700 | var div = create('div'); 701 | div.innerHTML = ''; 702 | return (div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg'; 703 | } 704 | 705 | // Borrowed from https://github.com/seiyria/bootstrap-slider/pull/680/files 706 | /* eslint-disable getter-return */ 707 | function testPassiveEventsSupport() { 708 | var passiveEvents = false; 709 | try { 710 | var opts = Object.defineProperty({}, 'passive', { 711 | get: function() { 712 | passiveEvents = true; 713 | } 714 | }); 715 | window.addEventListener('test', null, opts); 716 | } catch (e) { /* Silence the error and continue */ } 717 | 718 | return passiveEvents; 719 | } 720 | /* eslint-enable getter-return */ 721 | 722 | function preloadNext(index) { 723 | if (index - currentIndex >= options.preload) { 724 | return; 725 | } 726 | loadImage(index + 1, function() { 727 | preloadNext(index + 1); 728 | }); 729 | } 730 | 731 | function preloadPrev(index) { 732 | if (currentIndex - index >= options.preload) { 733 | return; 734 | } 735 | loadImage(index - 1, function() { 736 | preloadPrev(index - 1); 737 | }); 738 | } 739 | 740 | function bind(element, event, callback, options) { 741 | if (element.addEventListener) { 742 | element.addEventListener(event, callback, options); 743 | } else { 744 | // IE8 fallback 745 | element.attachEvent('on' + event, function(event) { 746 | // `event` and `event.target` are not provided in IE8 747 | event = event || window.event; 748 | event.target = event.target || event.srcElement; 749 | callback(event); 750 | }); 751 | } 752 | } 753 | 754 | function unbind(element, event, callback, options) { 755 | if (element.removeEventListener) { 756 | element.removeEventListener(event, callback, options); 757 | } else { 758 | // IE8 fallback 759 | element.detachEvent('on' + event, callback); 760 | } 761 | } 762 | 763 | function getByID(id) { 764 | return document.getElementById(id); 765 | } 766 | 767 | function create(element) { 768 | return document.createElement(element); 769 | } 770 | 771 | function destroyPlugin() { 772 | unbindEvents(); 773 | clearCachedData(); 774 | unbind(document, 'keydown', keyDownHandler); 775 | document.getElementsByTagName('body')[0].removeChild(document.getElementById('baguetteBox-overlay')); 776 | data = {}; 777 | currentGallery = []; 778 | currentIndex = 0; 779 | } 780 | 781 | return { 782 | run: run, 783 | show: show, 784 | showNext: showNextImage, 785 | showPrevious: showPreviousImage, 786 | hide: hideOverlay, 787 | destroy: destroyPlugin 788 | }; 789 | })); 790 | -------------------------------------------------------------------------------- /assets/src/scripts/_external/headroom.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * headroom.js v0.9.4 - Give your page some headroom. Hide your header until you need it 3 | * Copyright (c) 2017 Nick Williams - http://wicky.nillia.ms/headroom.js 4 | * License: MIT 5 | */ 6 | 7 | (function(root, factory) { 8 | 'use strict'; 9 | 10 | if (typeof define === 'function' && define.amd) { 11 | // AMD. Register as an anonymous module. 12 | define([], factory); 13 | } 14 | else if (typeof exports === 'object') { 15 | // COMMONJS 16 | module.exports = factory(); 17 | } 18 | else { 19 | // BROWSER 20 | root.Headroom = factory(); 21 | } 22 | }(this, function() { 23 | 'use strict'; 24 | 25 | /* exported features */ 26 | 27 | var features = { 28 | bind : !!(function(){}.bind), 29 | classList : 'classList' in document.documentElement, 30 | rAF : !!(window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame) 31 | }; 32 | window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; 33 | 34 | /** 35 | * Handles debouncing of events via requestAnimationFrame 36 | * @see http://www.html5rocks.com/en/tutorials/speed/animations/ 37 | * @param {Function} callback The callback to handle whichever event 38 | */ 39 | function Debouncer (callback) { 40 | this.callback = callback; 41 | this.ticking = false; 42 | } 43 | Debouncer.prototype = { 44 | constructor : Debouncer, 45 | 46 | /** 47 | * dispatches the event to the supplied callback 48 | * @private 49 | */ 50 | update : function() { 51 | this.callback && this.callback(); 52 | this.ticking = false; 53 | }, 54 | 55 | /** 56 | * ensures events don't get stacked 57 | * @private 58 | */ 59 | requestTick : function() { 60 | if(!this.ticking) { 61 | requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); 62 | this.ticking = true; 63 | } 64 | }, 65 | 66 | /** 67 | * Attach this as the event listeners 68 | */ 69 | handleEvent : function() { 70 | this.requestTick(); 71 | } 72 | }; 73 | /** 74 | * Check if object is part of the DOM 75 | * @constructor 76 | * @param {Object} obj element to check 77 | */ 78 | function isDOMElement(obj) { 79 | return obj && typeof window !== 'undefined' && (obj === window || obj.nodeType); 80 | } 81 | 82 | /** 83 | * Helper function for extending objects 84 | */ 85 | function extend (object /*, objectN ... */) { 86 | if(arguments.length <= 0) { 87 | throw new Error('Missing arguments in extend function'); 88 | } 89 | 90 | var result = object || {}, 91 | key, 92 | i; 93 | 94 | for (i = 1; i < arguments.length; i++) { 95 | var replacement = arguments[i] || {}; 96 | 97 | for (key in replacement) { 98 | // Recurse into object except if the object is a DOM element 99 | if(typeof result[key] === 'object' && ! isDOMElement(result[key])) { 100 | result[key] = extend(result[key], replacement[key]); 101 | } 102 | else { 103 | result[key] = result[key] || replacement[key]; 104 | } 105 | } 106 | } 107 | 108 | return result; 109 | } 110 | 111 | /** 112 | * Helper function for normalizing tolerance option to object format 113 | */ 114 | function normalizeTolerance (t) { 115 | return t === Object(t) ? t : { down : t, up : t }; 116 | } 117 | 118 | /** 119 | * UI enhancement for fixed headers. 120 | * Hides header when scrolling down 121 | * Shows header when scrolling up 122 | * @constructor 123 | * @param {DOMElement} elem the header element 124 | * @param {Object} options options for the widget 125 | */ 126 | function Headroom (elem, options) { 127 | options = extend(options, Headroom.options); 128 | 129 | this.lastKnownScrollY = 0; 130 | this.elem = elem; 131 | this.tolerance = normalizeTolerance(options.tolerance); 132 | this.classes = options.classes; 133 | this.offset = options.offset; 134 | this.scroller = options.scroller; 135 | this.initialised = false; 136 | this.onPin = options.onPin; 137 | this.onUnpin = options.onUnpin; 138 | this.onTop = options.onTop; 139 | this.onNotTop = options.onNotTop; 140 | this.onBottom = options.onBottom; 141 | this.onNotBottom = options.onNotBottom; 142 | } 143 | Headroom.prototype = { 144 | constructor : Headroom, 145 | 146 | /** 147 | * Initialises the widget 148 | */ 149 | init : function() { 150 | if(!Headroom.cutsTheMustard) { 151 | return; 152 | } 153 | 154 | this.debouncer = new Debouncer(this.update.bind(this)); 155 | this.elem.classList.add(this.classes.initial); 156 | 157 | // defer event registration to handle browser 158 | // potentially restoring previous scroll position 159 | setTimeout(this.attachEvent.bind(this), 100); 160 | 161 | return this; 162 | }, 163 | 164 | /** 165 | * Unattaches events and removes any classes that were added 166 | */ 167 | destroy : function() { 168 | var classes = this.classes; 169 | 170 | this.initialised = false; 171 | 172 | for (var key in classes) { 173 | if(classes.hasOwnProperty(key)) { 174 | this.elem.classList.remove(classes[key]); 175 | } 176 | } 177 | 178 | this.scroller.removeEventListener('scroll', this.debouncer, false); 179 | }, 180 | 181 | /** 182 | * Attaches the scroll event 183 | * @private 184 | */ 185 | attachEvent : function() { 186 | if(!this.initialised){ 187 | this.lastKnownScrollY = this.getScrollY(); 188 | this.initialised = true; 189 | this.scroller.addEventListener('scroll', this.debouncer, false); 190 | 191 | this.debouncer.handleEvent(); 192 | } 193 | }, 194 | 195 | /** 196 | * Unpins the header if it's currently pinned 197 | */ 198 | unpin : function() { 199 | var classList = this.elem.classList, 200 | classes = this.classes; 201 | 202 | if(classList.contains(classes.pinned) || !classList.contains(classes.unpinned)) { 203 | classList.add(classes.unpinned); 204 | classList.remove(classes.pinned); 205 | this.onUnpin && this.onUnpin.call(this); 206 | } 207 | }, 208 | 209 | /** 210 | * Pins the header if it's currently unpinned 211 | */ 212 | pin : function() { 213 | var classList = this.elem.classList, 214 | classes = this.classes; 215 | 216 | if(classList.contains(classes.unpinned)) { 217 | classList.remove(classes.unpinned); 218 | classList.add(classes.pinned); 219 | this.onPin && this.onPin.call(this); 220 | } 221 | }, 222 | 223 | /** 224 | * Handles the top states 225 | */ 226 | top : function() { 227 | var classList = this.elem.classList, 228 | classes = this.classes; 229 | 230 | if(!classList.contains(classes.top)) { 231 | classList.add(classes.top); 232 | classList.remove(classes.notTop); 233 | this.onTop && this.onTop.call(this); 234 | } 235 | }, 236 | 237 | /** 238 | * Handles the not top state 239 | */ 240 | notTop : function() { 241 | var classList = this.elem.classList, 242 | classes = this.classes; 243 | 244 | if(!classList.contains(classes.notTop)) { 245 | classList.add(classes.notTop); 246 | classList.remove(classes.top); 247 | this.onNotTop && this.onNotTop.call(this); 248 | } 249 | }, 250 | 251 | bottom : function() { 252 | var classList = this.elem.classList, 253 | classes = this.classes; 254 | 255 | if(!classList.contains(classes.bottom)) { 256 | classList.add(classes.bottom); 257 | classList.remove(classes.notBottom); 258 | this.onBottom && this.onBottom.call(this); 259 | } 260 | }, 261 | 262 | /** 263 | * Handles the not top state 264 | */ 265 | notBottom : function() { 266 | var classList = this.elem.classList, 267 | classes = this.classes; 268 | 269 | if(!classList.contains(classes.notBottom)) { 270 | classList.add(classes.notBottom); 271 | classList.remove(classes.bottom); 272 | this.onNotBottom && this.onNotBottom.call(this); 273 | } 274 | }, 275 | 276 | /** 277 | * Gets the Y scroll position 278 | * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY 279 | * @return {Number} pixels the page has scrolled along the Y-axis 280 | */ 281 | getScrollY : function() { 282 | return (this.scroller.pageYOffset !== undefined) 283 | ? this.scroller.pageYOffset 284 | : (this.scroller.scrollTop !== undefined) 285 | ? this.scroller.scrollTop 286 | : (document.documentElement || document.body.parentNode || document.body).scrollTop; 287 | }, 288 | 289 | /** 290 | * Gets the height of the viewport 291 | * @see http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript 292 | * @return {int} the height of the viewport in pixels 293 | */ 294 | getViewportHeight : function () { 295 | return window.innerHeight 296 | || document.documentElement.clientHeight 297 | || document.body.clientHeight; 298 | }, 299 | 300 | /** 301 | * Gets the physical height of the DOM element 302 | * @param {Object} elm the element to calculate the physical height of which 303 | * @return {int} the physical height of the element in pixels 304 | */ 305 | getElementPhysicalHeight : function (elm) { 306 | return Math.max( 307 | elm.offsetHeight, 308 | elm.clientHeight 309 | ); 310 | }, 311 | 312 | /** 313 | * Gets the physical height of the scroller element 314 | * @return {int} the physical height of the scroller element in pixels 315 | */ 316 | getScrollerPhysicalHeight : function () { 317 | return (this.scroller === window || this.scroller === document.body) 318 | ? this.getViewportHeight() 319 | : this.getElementPhysicalHeight(this.scroller); 320 | }, 321 | 322 | /** 323 | * Gets the height of the document 324 | * @see http://james.padolsey.com/javascript/get-document-height-cross-browser/ 325 | * @return {int} the height of the document in pixels 326 | */ 327 | getDocumentHeight : function () { 328 | var body = document.body, 329 | documentElement = document.documentElement; 330 | 331 | return Math.max( 332 | body.scrollHeight, documentElement.scrollHeight, 333 | body.offsetHeight, documentElement.offsetHeight, 334 | body.clientHeight, documentElement.clientHeight 335 | ); 336 | }, 337 | 338 | /** 339 | * Gets the height of the DOM element 340 | * @param {Object} elm the element to calculate the height of which 341 | * @return {int} the height of the element in pixels 342 | */ 343 | getElementHeight : function (elm) { 344 | return Math.max( 345 | elm.scrollHeight, 346 | elm.offsetHeight, 347 | elm.clientHeight 348 | ); 349 | }, 350 | 351 | /** 352 | * Gets the height of the scroller element 353 | * @return {int} the height of the scroller element in pixels 354 | */ 355 | getScrollerHeight : function () { 356 | return (this.scroller === window || this.scroller === document.body) 357 | ? this.getDocumentHeight() 358 | : this.getElementHeight(this.scroller); 359 | }, 360 | 361 | /** 362 | * determines if the scroll position is outside of document boundaries 363 | * @param {int} currentScrollY the current y scroll position 364 | * @return {bool} true if out of bounds, false otherwise 365 | */ 366 | isOutOfBounds : function (currentScrollY) { 367 | var pastTop = currentScrollY < 0, 368 | pastBottom = currentScrollY + this.getScrollerPhysicalHeight() > this.getScrollerHeight(); 369 | 370 | return pastTop || pastBottom; 371 | }, 372 | 373 | /** 374 | * determines if the tolerance has been exceeded 375 | * @param {int} currentScrollY the current scroll y position 376 | * @return {bool} true if tolerance exceeded, false otherwise 377 | */ 378 | toleranceExceeded : function (currentScrollY, direction) { 379 | return Math.abs(currentScrollY-this.lastKnownScrollY) >= this.tolerance[direction]; 380 | }, 381 | 382 | /** 383 | * determine if it is appropriate to unpin 384 | * @param {int} currentScrollY the current y scroll position 385 | * @param {bool} toleranceExceeded has the tolerance been exceeded? 386 | * @return {bool} true if should unpin, false otherwise 387 | */ 388 | shouldUnpin : function (currentScrollY, toleranceExceeded) { 389 | var scrollingDown = currentScrollY > this.lastKnownScrollY, 390 | pastOffset = currentScrollY >= this.offset; 391 | 392 | return scrollingDown && pastOffset && toleranceExceeded; 393 | }, 394 | 395 | /** 396 | * determine if it is appropriate to pin 397 | * @param {int} currentScrollY the current y scroll position 398 | * @param {bool} toleranceExceeded has the tolerance been exceeded? 399 | * @return {bool} true if should pin, false otherwise 400 | */ 401 | shouldPin : function (currentScrollY, toleranceExceeded) { 402 | var scrollingUp = currentScrollY < this.lastKnownScrollY, 403 | pastOffset = currentScrollY <= this.offset; 404 | 405 | return (scrollingUp && toleranceExceeded) || pastOffset; 406 | }, 407 | 408 | /** 409 | * Handles updating the state of the widget 410 | */ 411 | update : function() { 412 | var currentScrollY = this.getScrollY(), 413 | scrollDirection = currentScrollY > this.lastKnownScrollY ? 'down' : 'up', 414 | toleranceExceeded = this.toleranceExceeded(currentScrollY, scrollDirection); 415 | 416 | if(this.isOutOfBounds(currentScrollY)) { // Ignore bouncy scrolling in OSX 417 | return; 418 | } 419 | 420 | if (currentScrollY <= this.offset ) { 421 | this.top(); 422 | } else { 423 | this.notTop(); 424 | } 425 | 426 | if(currentScrollY + this.getViewportHeight() >= this.getScrollerHeight()) { 427 | this.bottom(); 428 | } 429 | else { 430 | this.notBottom(); 431 | } 432 | 433 | if(this.shouldUnpin(currentScrollY, toleranceExceeded)) { 434 | this.unpin(); 435 | } 436 | else if(this.shouldPin(currentScrollY, toleranceExceeded)) { 437 | this.pin(); 438 | } 439 | 440 | this.lastKnownScrollY = currentScrollY; 441 | } 442 | }; 443 | /** 444 | * Default options 445 | * @type {Object} 446 | */ 447 | Headroom.options = { 448 | tolerance : { 449 | up : 0, 450 | down : 0 451 | }, 452 | offset : 0, 453 | scroller: window, 454 | classes : { 455 | pinned : 'headroom--pinned', 456 | unpinned : 'headroom--unpinned', 457 | top : 'headroom--top', 458 | notTop : 'headroom--not-top', 459 | bottom : 'headroom--bottom', 460 | notBottom : 'headroom--not-bottom', 461 | initial : 'headroom' 462 | } 463 | }; 464 | Headroom.cutsTheMustard = typeof features !== 'undefined' && features.rAF && features.bind && features.classList; 465 | 466 | return Headroom; 467 | })); -------------------------------------------------------------------------------- /assets/src/scripts/_external/lazyload.js: -------------------------------------------------------------------------------- 1 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 2 | 3 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; 4 | 5 | (function (global, factory) { 6 | (typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.LazyLoad = factory(); 7 | })(this, function () { 8 | 'use strict'; 9 | 10 | var defaultSettings = { 11 | elements_selector: "img", 12 | container: document, 13 | threshold: 300, 14 | thresholds: null, 15 | data_src: "src", 16 | data_srcset: "srcset", 17 | data_sizes: "sizes", 18 | data_bg: "bg", 19 | class_loading: "loading", 20 | class_loaded: "loaded", 21 | class_error: "error", 22 | load_delay: 0, 23 | callback_load: null, 24 | callback_error: null, 25 | callback_set: null, 26 | callback_enter: null, 27 | to_webp: false 28 | }; 29 | 30 | var getInstanceSettings = function getInstanceSettings(customSettings) { 31 | return _extends({}, defaultSettings, customSettings); 32 | }; 33 | 34 | var dataPrefix = "data-"; 35 | var processedDataName = "was-processed"; 36 | var timeoutDataName = "ll-timeout"; 37 | var trueString = "true"; 38 | 39 | var getData = function getData(element, attribute) { 40 | return element.getAttribute(dataPrefix + attribute); 41 | }; 42 | 43 | var setData = function setData(element, attribute, value) { 44 | var attrName = dataPrefix + attribute; 45 | if (value === null) { 46 | element.removeAttribute(attrName); 47 | return; 48 | } 49 | element.setAttribute(attrName, value); 50 | }; 51 | 52 | var setWasProcessedData = function setWasProcessedData(element) { 53 | return setData(element, processedDataName, trueString); 54 | }; 55 | 56 | var getWasProcessedData = function getWasProcessedData(element) { 57 | return getData(element, processedDataName) === trueString; 58 | }; 59 | 60 | var setTimeoutData = function setTimeoutData(element, value) { 61 | return setData(element, timeoutDataName, value); 62 | }; 63 | 64 | var getTimeoutData = function getTimeoutData(element) { 65 | return getData(element, timeoutDataName); 66 | }; 67 | 68 | function purgeElements(elements) { 69 | return elements.filter(function (element) { 70 | return !getWasProcessedData(element); 71 | }); 72 | } 73 | 74 | /* Creates instance and notifies it through the window element */ 75 | var createInstance = function createInstance(classObj, options) { 76 | var event; 77 | var eventString = "LazyLoad::Initialized"; 78 | var instance = new classObj(options); 79 | try { 80 | // Works in modern browsers 81 | event = new CustomEvent(eventString, { detail: { instance: instance } }); 82 | } catch (err) { 83 | // Works in Internet Explorer (all versions) 84 | event = document.createEvent("CustomEvent"); 85 | event.initCustomEvent(eventString, false, false, { instance: instance }); 86 | } 87 | window.dispatchEvent(event); 88 | }; 89 | 90 | /* Auto initialization of one or more instances of lazyload, depending on the 91 | options passed in (plain object or an array) */ 92 | function autoInitialize(classObj, options) { 93 | if (!options) { 94 | return; 95 | } 96 | if (!options.length) { 97 | // Plain object 98 | createInstance(classObj, options); 99 | } else { 100 | // Array of objects 101 | for (var i = 0, optionsItem; optionsItem = options[i]; i += 1) { 102 | createInstance(classObj, optionsItem); 103 | } 104 | } 105 | } 106 | 107 | var replaceExtToWebp = function replaceExtToWebp(value, condition) { 108 | return condition ? value.replace(/\.(jpe?g|png)/gi, ".webp") : value; 109 | }; 110 | 111 | var detectWebp = function detectWebp() { 112 | var webpString = "image/webp"; 113 | var canvas = document.createElement("canvas"); 114 | 115 | if (canvas.getContext && canvas.getContext("2d")) { 116 | return canvas.toDataURL(webpString).indexOf('data:' + webpString) === 0; 117 | } 118 | 119 | return false; 120 | }; 121 | 122 | var runningOnBrowser = typeof window !== "undefined"; 123 | 124 | var isBot = runningOnBrowser && !("onscroll" in window) || /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent); 125 | 126 | var supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window; 127 | 128 | var supportsClassList = runningOnBrowser && "classList" in document.createElement("p"); 129 | 130 | var supportsWebp = runningOnBrowser && detectWebp(); 131 | 132 | var setSourcesInChildren = function setSourcesInChildren(parentTag, attrName, dataAttrName, toWebpFlag) { 133 | for (var i = 0, childTag; childTag = parentTag.children[i]; i += 1) { 134 | if (childTag.tagName === "SOURCE") { 135 | var attrValue = getData(childTag, dataAttrName); 136 | setAttributeIfValue(childTag, attrName, attrValue, toWebpFlag); 137 | } 138 | } 139 | }; 140 | 141 | var setAttributeIfValue = function setAttributeIfValue(element, attrName, value, toWebpFlag) { 142 | if (!value) { 143 | return; 144 | } 145 | element.setAttribute(attrName, replaceExtToWebp(value, toWebpFlag)); 146 | }; 147 | 148 | var setSourcesImg = function setSourcesImg(element, settings) { 149 | var toWebpFlag = supportsWebp && settings.to_webp; 150 | var srcsetDataName = settings.data_srcset; 151 | var parent = element.parentNode; 152 | 153 | if (parent && parent.tagName === "PICTURE") { 154 | setSourcesInChildren(parent, "srcset", srcsetDataName, toWebpFlag); 155 | } 156 | var sizesDataValue = getData(element, settings.data_sizes); 157 | setAttributeIfValue(element, "sizes", sizesDataValue); 158 | var srcsetDataValue = getData(element, srcsetDataName); 159 | setAttributeIfValue(element, "srcset", srcsetDataValue, toWebpFlag); 160 | var srcDataValue = getData(element, settings.data_src); 161 | setAttributeIfValue(element, "src", srcDataValue, toWebpFlag); 162 | }; 163 | 164 | var setSourcesIframe = function setSourcesIframe(element, settings) { 165 | var srcDataValue = getData(element, settings.data_src); 166 | 167 | setAttributeIfValue(element, "src", srcDataValue); 168 | }; 169 | 170 | var setSourcesVideo = function setSourcesVideo(element, settings) { 171 | var srcDataName = settings.data_src; 172 | var srcDataValue = getData(element, srcDataName); 173 | 174 | setSourcesInChildren(element, "src", srcDataName); 175 | setAttributeIfValue(element, "src", srcDataValue); 176 | element.load(); 177 | }; 178 | 179 | var setSourcesBgImage = function setSourcesBgImage(element, settings) { 180 | var toWebpFlag = supportsWebp && settings.to_webp; 181 | var srcDataValue = getData(element, settings.data_src); 182 | var bgDataValue = getData(element, settings.data_bg); 183 | 184 | if (srcDataValue) { 185 | var setValue = replaceExtToWebp(srcDataValue, toWebpFlag); 186 | element.style.backgroundImage = 'url("' + setValue + '")'; 187 | } 188 | 189 | if (bgDataValue) { 190 | var _setValue = replaceExtToWebp(bgDataValue, toWebpFlag); 191 | element.style.backgroundImage = _setValue; 192 | } 193 | }; 194 | 195 | var setSourcesFunctions = { 196 | IMG: setSourcesImg, 197 | IFRAME: setSourcesIframe, 198 | VIDEO: setSourcesVideo 199 | }; 200 | 201 | var setSources = function setSources(element, settings) { 202 | var tagName = element.tagName; 203 | var setSourcesFunction = setSourcesFunctions[tagName]; 204 | if (setSourcesFunction) { 205 | setSourcesFunction(element, settings); 206 | return; 207 | } 208 | setSourcesBgImage(element, settings); 209 | }; 210 | 211 | var addClass = function addClass(element, className) { 212 | if (supportsClassList) { 213 | element.classList.add(className); 214 | return; 215 | } 216 | element.className += (element.className ? " " : "") + className; 217 | }; 218 | 219 | var removeClass = function removeClass(element, className) { 220 | if (supportsClassList) { 221 | element.classList.remove(className); 222 | return; 223 | } 224 | element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), " ").replace(/^\s+/, "").replace(/\s+$/, ""); 225 | }; 226 | 227 | var callbackIfSet = function callbackIfSet(callback, argument) { 228 | if (callback) { 229 | callback(argument); 230 | } 231 | }; 232 | 233 | var genericLoadEventName = "load"; 234 | var mediaLoadEventName = "loadeddata"; 235 | var errorEventName = "error"; 236 | 237 | var addEventListener = function addEventListener(element, eventName, handler) { 238 | element.addEventListener(eventName, handler); 239 | }; 240 | 241 | var removeEventListener = function removeEventListener(element, eventName, handler) { 242 | element.removeEventListener(eventName, handler); 243 | }; 244 | 245 | var addAllEventListeners = function addAllEventListeners(element, loadHandler, errorHandler) { 246 | addEventListener(element, genericLoadEventName, loadHandler); 247 | addEventListener(element, mediaLoadEventName, loadHandler); 248 | addEventListener(element, errorEventName, errorHandler); 249 | }; 250 | 251 | var removeAllEventListeners = function removeAllEventListeners(element, loadHandler, errorHandler) { 252 | removeEventListener(element, genericLoadEventName, loadHandler); 253 | removeEventListener(element, mediaLoadEventName, loadHandler); 254 | removeEventListener(element, errorEventName, errorHandler); 255 | }; 256 | 257 | var eventHandler = function eventHandler(event, success, settings) { 258 | var className = success ? settings.class_loaded : settings.class_error; 259 | var callback = success ? settings.callback_load : settings.callback_error; 260 | var element = event.target; 261 | 262 | removeClass(element, settings.class_loading); 263 | addClass(element, className); 264 | callbackIfSet(callback, element); 265 | }; 266 | 267 | var addOneShotEventListeners = function addOneShotEventListeners(element, settings) { 268 | var loadHandler = function loadHandler(event) { 269 | eventHandler(event, true, settings); 270 | removeAllEventListeners(element, loadHandler, errorHandler); 271 | }; 272 | var errorHandler = function errorHandler(event) { 273 | eventHandler(event, false, settings); 274 | removeAllEventListeners(element, loadHandler, errorHandler); 275 | }; 276 | addAllEventListeners(element, loadHandler, errorHandler); 277 | }; 278 | 279 | var managedTags = ["IMG", "IFRAME", "VIDEO"]; 280 | 281 | var loadAndUnobserve = function loadAndUnobserve(element, observer, settings) { 282 | revealElement(element, settings); 283 | observer.unobserve(element); 284 | }; 285 | 286 | var cancelDelayLoad = function cancelDelayLoad(element) { 287 | var timeoutId = getTimeoutData(element); 288 | if (!timeoutId) { 289 | return; // do nothing if timeout doesn't exist 290 | } 291 | clearTimeout(timeoutId); 292 | setTimeoutData(element, null); 293 | }; 294 | 295 | var delayLoad = function delayLoad(element, observer, settings) { 296 | var loadDelay = settings.load_delay; 297 | var timeoutId = getTimeoutData(element); 298 | if (timeoutId) { 299 | return; // do nothing if timeout already set 300 | } 301 | timeoutId = setTimeout(function () { 302 | loadAndUnobserve(element, observer, settings); 303 | cancelDelayLoad(element); 304 | }, loadDelay); 305 | setTimeoutData(element, timeoutId); 306 | }; 307 | 308 | function revealElement(element, settings, force) { 309 | if (!force && getWasProcessedData(element)) { 310 | return; // element has already been processed and force wasn't true 311 | } 312 | callbackIfSet(settings.callback_enter, element); 313 | if (managedTags.indexOf(element.tagName) > -1) { 314 | addOneShotEventListeners(element, settings); 315 | addClass(element, settings.class_loading); 316 | } 317 | setSources(element, settings); 318 | setWasProcessedData(element); 319 | callbackIfSet(settings.callback_set, element); 320 | } 321 | 322 | /* entry.isIntersecting needs fallback because is null on some versions of MS Edge, and 323 | entry.intersectionRatio is not enough alone because it could be 0 on some intersecting elements */ 324 | var isIntersecting = function isIntersecting(entry) { 325 | return entry.isIntersecting || entry.intersectionRatio > 0; 326 | }; 327 | 328 | var getObserverSettings = function getObserverSettings(settings) { 329 | return { 330 | root: settings.container === document ? null : settings.container, 331 | rootMargin: settings.thresholds || settings.threshold + "px" 332 | }; 333 | }; 334 | 335 | var LazyLoad = function LazyLoad(customSettings, elements) { 336 | this._settings = getInstanceSettings(customSettings); 337 | this._setObserver(); 338 | this.update(elements); 339 | }; 340 | 341 | LazyLoad.prototype = { 342 | _manageIntersection: function _manageIntersection(entry) { 343 | var observer = this._observer; 344 | var settings = this._settings; 345 | var loadDelay = this._settings.load_delay; 346 | var element = entry.target; 347 | if (isIntersecting(entry)) { 348 | if (!loadDelay) { 349 | loadAndUnobserve(element, observer, settings); 350 | } else { 351 | delayLoad(element, observer, settings); 352 | } 353 | } 354 | 355 | // Writes in and outs in a data-attribute 356 | if (!isIntersecting(entry)) { 357 | cancelDelayLoad(element); 358 | } 359 | }, 360 | _onIntersection: function _onIntersection(entries) { 361 | entries.forEach(this._manageIntersection.bind(this)); 362 | this._elements = purgeElements(this._elements); 363 | }, 364 | _setObserver: function _setObserver() { 365 | if (!supportsIntersectionObserver) { 366 | return; 367 | } 368 | this._observer = new IntersectionObserver(this._onIntersection.bind(this), getObserverSettings(this._settings)); 369 | }, 370 | 371 | loadAll: function loadAll() { 372 | var _this = this; 373 | 374 | this._elements.forEach(function (element) { 375 | _this.load(element); 376 | }); 377 | this._elements = purgeElements(this._elements); 378 | }, 379 | 380 | update: function update(elements) { 381 | var _this2 = this; 382 | 383 | var settings = this._settings; 384 | var nodeSet = elements || settings.container.querySelectorAll(settings.elements_selector); 385 | 386 | this._elements = purgeElements(Array.prototype.slice.call(nodeSet)); // nodeset to array for IE compatibility 387 | 388 | if (isBot || !this._observer) { 389 | this.loadAll(); 390 | return; 391 | } 392 | 393 | this._elements.forEach(function (element) { 394 | _this2._observer.observe(element); 395 | }); 396 | }, 397 | 398 | destroy: function destroy() { 399 | var _this3 = this; 400 | 401 | if (this._observer) { 402 | purgeElements(this._elements).forEach(function (element) { 403 | _this3._observer.unobserve(element); 404 | }); 405 | this._observer = null; 406 | } 407 | this._elements = null; 408 | this._settings = null; 409 | }, 410 | 411 | load: function load(element, force) { 412 | revealElement(element, this._settings, force); 413 | } 414 | }; 415 | 416 | /* Automatic instances creation if required (useful for async script loading) */ 417 | if (runningOnBrowser) { 418 | autoInitialize(LazyLoad, window.lazyLoadOptions); 419 | } 420 | 421 | return LazyLoad; 422 | }); -------------------------------------------------------------------------------- /assets/src/scripts/main.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function(event) { 2 | // LazdyLoad 3 | const myLazyLoad = new LazyLoad() 4 | 5 | // Lightbox 6 | baguetteBox.run('main', {}) 7 | 8 | // Hide header 9 | const navbar = document.querySelector('nav') 10 | if (navbar) { 11 | const headroom = new Headroom(navbar, { 12 | 'offset': 205, 13 | 'tolerance': 5, 14 | 'classes': { 15 | 'initial': 'animated', 16 | 'pinned': 'slideDown', 17 | 'unpinned': 'slideUp' 18 | } 19 | }) 20 | headroom.init() 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /assets/src/styles/_chroma_friendly.scss: -------------------------------------------------------------------------------- 1 | /* Background */ .chroma { background-color: #f0f0f0 } 2 | /* Error */ .chroma .err { } 3 | /* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } 4 | /* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; } 5 | /* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc } 6 | /* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; } 7 | /* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; } 8 | /* Keyword */ .chroma .k { color: #007020; font-weight: bold } 9 | /* KeywordConstant */ .chroma .kc { color: #007020; font-weight: bold } 10 | /* KeywordDeclaration */ .chroma .kd { color: #007020; font-weight: bold } 11 | /* KeywordNamespace */ .chroma .kn { color: #007020; font-weight: bold } 12 | /* KeywordPseudo */ .chroma .kp { color: #007020 } 13 | /* KeywordReserved */ .chroma .kr { color: #007020; font-weight: bold } 14 | /* KeywordType */ .chroma .kt { color: #902000 } 15 | /* NameAttribute */ .chroma .na { color: #4070a0 } 16 | /* NameBuiltin */ .chroma .nb { color: #007020 } 17 | /* NameClass */ .chroma .nc { color: #0e84b5; font-weight: bold } 18 | /* NameConstant */ .chroma .no { color: #60add5 } 19 | /* NameDecorator */ .chroma .nd { color: #555555; font-weight: bold } 20 | /* NameEntity */ .chroma .ni { color: #d55537; font-weight: bold } 21 | /* NameException */ .chroma .ne { color: #007020 } 22 | /* NameFunction */ .chroma .nf { color: #06287e } 23 | /* NameLabel */ .chroma .nl { color: #002070; font-weight: bold } 24 | /* NameNamespace */ .chroma .nn { color: #0e84b5; font-weight: bold } 25 | /* NameTag */ .chroma .nt { color: #062873; font-weight: bold } 26 | /* NameVariable */ .chroma .nv { color: #bb60d5 } 27 | /* LiteralString */ .chroma .s { color: #4070a0 } 28 | /* LiteralStringAffix */ .chroma .sa { color: #4070a0 } 29 | /* LiteralStringBacktick */ .chroma .sb { color: #4070a0 } 30 | /* LiteralStringChar */ .chroma .sc { color: #4070a0 } 31 | /* LiteralStringDelimiter */ .chroma .dl { color: #4070a0 } 32 | /* LiteralStringDoc */ .chroma .sd { color: #4070a0; font-style: italic } 33 | /* LiteralStringDouble */ .chroma .s2 { color: #4070a0 } 34 | /* LiteralStringEscape */ .chroma .se { color: #4070a0; font-weight: bold } 35 | /* LiteralStringHeredoc */ .chroma .sh { color: #4070a0 } 36 | /* LiteralStringInterpol */ .chroma .si { color: #70a0d0; font-style: italic } 37 | /* LiteralStringOther */ .chroma .sx { color: #c65d09 } 38 | /* LiteralStringRegex */ .chroma .sr { color: #235388 } 39 | /* LiteralStringSingle */ .chroma .s1 { color: #4070a0 } 40 | /* LiteralStringSymbol */ .chroma .ss { color: #517918 } 41 | /* LiteralNumber */ .chroma .m { color: #40a070 } 42 | /* LiteralNumberBin */ .chroma .mb { color: #40a070 } 43 | /* LiteralNumberFloat */ .chroma .mf { color: #40a070 } 44 | /* LiteralNumberHex */ .chroma .mh { color: #40a070 } 45 | /* LiteralNumberInteger */ .chroma .mi { color: #40a070 } 46 | /* LiteralNumberIntegerLong */ .chroma .il { color: #40a070 } 47 | /* LiteralNumberOct */ .chroma .mo { color: #40a070 } 48 | /* Operator */ .chroma .o { color: #666666 } 49 | /* OperatorWord */ .chroma .ow { color: #007020; font-weight: bold } 50 | /* Comment */ .chroma .c { color: #60a0b0; font-style: italic } 51 | /* CommentHashbang */ .chroma .ch { color: #60a0b0; font-style: italic } 52 | /* CommentMultiline */ .chroma .cm { color: #60a0b0; font-style: italic } 53 | /* CommentSingle */ .chroma .c1 { color: #60a0b0; font-style: italic } 54 | /* CommentSpecial */ .chroma .cs { color: #60a0b0; background-color: #fff0f0 } 55 | /* CommentPreproc */ .chroma .cp { color: #007020 } 56 | /* CommentPreprocFile */ .chroma .cpf { color: #007020 } 57 | /* GenericDeleted */ .chroma .gd { color: #a00000 } 58 | /* GenericEmph */ .chroma .ge { font-style: italic } 59 | /* GenericError */ .chroma .gr { color: #ff0000 } 60 | /* GenericHeading */ .chroma .gh { color: #000080; font-weight: bold } 61 | /* GenericInserted */ .chroma .gi { color: #00a000 } 62 | /* GenericOutput */ .chroma .go { color: #888888 } 63 | /* GenericPrompt */ .chroma .gp { color: #c65d09; font-weight: bold } 64 | /* GenericStrong */ .chroma .gs { font-weight: bold } 65 | /* GenericSubheading */ .chroma .gu { color: #800080; font-weight: bold } 66 | /* GenericTraceback */ .chroma .gt { color: #0044dd } 67 | /* GenericUnderline */ .chroma .gl { text-decoration: underline } 68 | /* TextWhitespace */ .chroma .w { color: #bbbbbb } 69 | -------------------------------------------------------------------------------- /assets/src/styles/_components/base.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | background-color: $base-background-color; 3 | font-family: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 4 | height: 100%; 5 | margin: 0; 6 | text-rendering: optimizeLegibility; 7 | } 8 | 9 | body { 10 | display: grid; 11 | grid-gap: 1rem; 12 | grid-template-areas: "nav" "main" "footer"; 13 | grid-template-columns: 1fr; 14 | height: 100%; 15 | 16 | grid-template-rows: $navbar-height 1fr 3rem; 17 | @media screen and (max-width: $breakpoint) { 18 | grid-template-rows: $navbar-height 1fr 5rem; 19 | } 20 | 21 | a { 22 | color: $links-color; 23 | text-decoration: none; 24 | 25 | &:hover, &:active, &:visited { 26 | text-decoration: underline; 27 | } 28 | } 29 | 30 | nav { 31 | grid-area: nav; 32 | } 33 | 34 | main { 35 | grid-area: main; 36 | justify-self: center; 37 | grid-column: 1 / -1; 38 | max-width: 80rem !important; 39 | padding-bottom: 3rem !important; 40 | padding-top: 3rem !important; 41 | 42 | &.home { 43 | align-items: center; 44 | display: flex; 45 | flex-direction: column; 46 | justify-content: center; 47 | text-align: center; 48 | } 49 | } 50 | 51 | footer { 52 | grid-area: footer; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /assets/src/styles/_components/content.scss: -------------------------------------------------------------------------------- 1 | body { 2 | main { 3 | article { 4 | header { 5 | margin-bottom: 5rem; 6 | text-align: center; 7 | 8 | time { 9 | color: $color-silver; 10 | } 11 | } 12 | 13 | section { 14 | ins.adsbygoogle, 15 | video { 16 | margin: 5rem auto; 17 | } 18 | 19 | figure { 20 | margin: $itemMargin 0; 21 | 22 | &.full { 23 | left: 50%; 24 | margin-left: -50vw; 25 | margin-right: -50vw; 26 | position: relative; 27 | right: 50%; 28 | width: 100vw; 29 | } 30 | 31 | img { 32 | display: block; 33 | height: auto; 34 | margin: 0 auto; 35 | max-width: 100%; 36 | padding: 0; 37 | 38 | &.full { 39 | left: 50%; 40 | margin-left: -50vw; 41 | margin-right: -50vw; 42 | position: relative; 43 | right: 50%; 44 | width: 100vw; 45 | } 46 | } 47 | 48 | figcaption { 49 | text-align: center; 50 | } 51 | } 52 | 53 | table { 54 | tbody { 55 | tr { 56 | td { 57 | &[align="left"] { 58 | text-align: left; 59 | } 60 | &[align="right"] { 61 | text-align: right; 62 | } 63 | &[align="center"] { 64 | text-align: center; 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | pre { 72 | border-left: 0.3rem solid $links-color; 73 | display: grid; 74 | // overflow: auto; 75 | 76 | code { 77 | background-color: transparent; 78 | min-width: 0; 79 | } 80 | } 81 | 82 | .gist { 83 | width: 100%; 84 | 85 | & table { 86 | table-layout: fixed; 87 | } 88 | 89 | & td.js-line-number{ 90 | width: 50px; 91 | text-align: center; 92 | } 93 | } 94 | 95 | iframe.instagram-media { 96 | margin-left: auto !important; 97 | margin-right: auto !important; 98 | } 99 | 100 | img { 101 | display: block; 102 | height: auto; 103 | margin: $itemMargin auto; 104 | max-width: 100%; 105 | padding: 0; 106 | 107 | &.full { 108 | left: 50%; 109 | margin-left: -50vw; 110 | margin-right: -50vw; 111 | position: relative; 112 | right: 50%; 113 | width: 100vw; 114 | } 115 | } 116 | 117 | p { 118 | code { 119 | background-color: $color-zhen-zhu-bai-pearl; 120 | color: $color-bara-red; 121 | white-space: normal; 122 | 123 | /* These are technically the same, but use both */ 124 | overflow-wrap: break-word; 125 | word-wrap: break-word; 126 | 127 | -ms-word-break: break-all; 128 | /* This is the dangerous one in WebKit, as it breaks things wherever */ 129 | word-break: break-all; 130 | /* Instead use this non-standard one: */ 131 | word-break: break-word; 132 | 133 | /* Adds a hyphen where the word breaks, if supported (No Blink) */ 134 | -ms-hyphens: auto; 135 | -moz-hyphens: auto; 136 | -webkit-hyphens: auto; 137 | hyphens: auto; 138 | } 139 | } 140 | 141 | ul { 142 | &.task-list { 143 | list-style: none; 144 | padding: 0; 145 | } 146 | } 147 | 148 | ol { 149 | list-style: decimal; 150 | } 151 | 152 | video { 153 | display: block; 154 | width: 100% 155 | } 156 | 157 | .embed-container { 158 | height: 0; 159 | max-width: 100%; 160 | overflow: hidden; 161 | padding-bottom: 56.25%; 162 | position: relative; 163 | 164 | embed, iframe, object { 165 | height: 100%; 166 | left: 0; 167 | position: absolute; 168 | top: 0; 169 | width: 100%; 170 | } 171 | } 172 | 173 | .speakerdeck { 174 | margin-left: auto !important; 175 | margin-right: auto !important; 176 | } 177 | 178 | .twitter-tweet { 179 | @media (max-width: 550px) { 180 | width: 0 !important; 181 | } 182 | 183 | margin-left: auto !important; 184 | margin-right: auto !important; 185 | } 186 | } 187 | 188 | footer { 189 | text-align: center; 190 | 191 | .meta { 192 | .tags { 193 | a { 194 | span { 195 | color: $color-silver; 196 | } 197 | } 198 | } 199 | } 200 | 201 | #disqus_thread { 202 | margin-left: auto !important; 203 | margin-right: auto !important; 204 | } 205 | } 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /assets/src/styles/_components/elements.scss: -------------------------------------------------------------------------------- 1 | ul.posts-list { 2 | list-style: none; 3 | 4 | li { 5 | .date { 6 | color: $color-silver; 7 | font-size: 0.8em; 8 | display: block; 9 | } 10 | 11 | .lang { 12 | color: $color-silver; 13 | font-size: 0.7em; 14 | text-transform: uppercase; 15 | 16 | a { 17 | color: $color-silver; 18 | text-decoration: none; 19 | 20 | &:hover, &:active, &:visited { 21 | text-decoration: underline; 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /assets/src/styles/_components/footer.scss: -------------------------------------------------------------------------------- 1 | body { 2 | > footer { 3 | align-items: right; 4 | color: $navbar-text-color; 5 | display: flex; 6 | font-size: 0.8em; 7 | justify-content: space-between; 8 | padding: 0.5rem; 9 | text-align: center; 10 | 11 | p { 12 | margin-bottom: 0; 13 | } 14 | 15 | // height: 3rem; 16 | // @media screen and (max-width: $breakpoint) { 17 | // height: 5rem; 18 | // } 19 | 20 | @media screen and (max-width: $breakpoint) { 21 | flex-direction: column; 22 | 23 | p { 24 | &:first-of-type { 25 | margin-bottom: 0.1rem; 26 | } 27 | &:last-of-type { 28 | margin-top: 0.1rem; 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /assets/src/styles/_components/homepage.scss: -------------------------------------------------------------------------------- 1 | body { 2 | main { 3 | .homepage-avatar { 4 | border-radius: 50%; 5 | margin-bottom: 2rem; 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /assets/src/styles/_components/navbar.scss: -------------------------------------------------------------------------------- 1 | body { 2 | nav { 3 | align-items: center; 4 | background-color: #f4f5f6; 5 | color: $navbar-text-color; 6 | display: flex; 7 | height: $navbar-height; 8 | justify-content: space-between; 9 | left: 0; 10 | padding: 0.1rem 1rem; 11 | position: fixed; 12 | right: 0; 13 | top: 0; 14 | z-index: 10; 15 | border-bottom: .1rem solid #d1d1d1; 16 | 17 | a { 18 | color: $navbar-text-color; 19 | text-decoration: none; 20 | 21 | &:hover, &:active, &:visited { 22 | text-decoration: none; 23 | } 24 | } 25 | 26 | &.animated { 27 | animation-duration: 0.5s; 28 | animation-fill-mode: both; 29 | will-change: transform, opacity; 30 | 31 | &.slideDown { 32 | animation-name: slideDown; 33 | } 34 | 35 | &.slideUp { 36 | animation-name: slideUp; 37 | } 38 | } 39 | } 40 | } 41 | 42 | @-webkit-keyframes slideUp { 43 | 0% { 44 | -webkit-transform: translateY(0); 45 | } 46 | 47 | 100% { 48 | -webkit-transform: translateY(-100%); 49 | } 50 | } 51 | 52 | @-moz-keyframes slideUp { 53 | 0% { 54 | -moz-transform: translateY(0); 55 | } 56 | 57 | 100% { 58 | -moz-transform: translateY(-100%); 59 | } 60 | } 61 | 62 | @-o-keyframes slideUp { 63 | 0% { 64 | -o-transform: translateY(0); 65 | } 66 | 67 | 100% { 68 | -o-transform: translateY(-100%); 69 | } 70 | } 71 | 72 | @keyframes slideUp { 73 | 0% { 74 | transform: translateY(0); 75 | } 76 | 77 | 100% { 78 | transform: translateY(-100%); 79 | } 80 | } 81 | 82 | @-webkit-keyframes slideDown { 83 | 0% { 84 | -webkit-transform: translateY(-100%); 85 | } 86 | 87 | 100% { 88 | -webkit-transform: translateY(0); 89 | } 90 | } 91 | 92 | @-moz-keyframes slideDown { 93 | 0% { 94 | -moz-transform: translateY(-100%); 95 | } 96 | 97 | 100% { 98 | -moz-transform: translateY(0); 99 | } 100 | } 101 | 102 | @-o-keyframes slideDown { 103 | 0% { 104 | -o-transform: translateY(-100%); 105 | } 106 | 107 | 100% { 108 | -o-transform: translateY(0); 109 | } 110 | } 111 | 112 | @keyframes slideDown { 113 | 0% { 114 | transform: translateY(-100%); 115 | } 116 | 117 | 100% { 118 | transform: translateY(0); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /assets/src/styles/_external/baguetteBox.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * baguetteBox.js 3 | * @author feimosi 4 | * @version 1.11.0 5 | * @url https://github.com/feimosi/baguetteBox.js 6 | */ 7 | #baguetteBox-overlay { 8 | display: none; 9 | opacity: 0; 10 | position: fixed; 11 | overflow: hidden; 12 | top: 0; 13 | left: 0; 14 | width: 100%; 15 | height: 100%; 16 | z-index: 1000000; 17 | background-color: #222; 18 | background-color: rgba(0, 0, 0, 0.8); 19 | -webkit-transition: opacity .5s ease; 20 | transition: opacity .5s ease; } 21 | #baguetteBox-overlay.visible { 22 | opacity: 1; } 23 | #baguetteBox-overlay .full-image { 24 | display: inline-block; 25 | position: relative; 26 | width: 100%; 27 | height: 100%; 28 | text-align: center; } 29 | #baguetteBox-overlay .full-image figure { 30 | display: inline; 31 | margin: 0; 32 | height: 100%; } 33 | #baguetteBox-overlay .full-image img { 34 | display: inline-block; 35 | width: auto; 36 | height: auto; 37 | max-height: 100%; 38 | max-width: 100%; 39 | vertical-align: middle; 40 | -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); 41 | -moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); 42 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); } 43 | #baguetteBox-overlay .full-image figcaption { 44 | display: block; 45 | position: absolute; 46 | bottom: 0; 47 | width: 100%; 48 | text-align: center; 49 | line-height: 1.8; 50 | white-space: normal; 51 | color: #ccc; 52 | background-color: #000; 53 | background-color: rgba(0, 0, 0, 0.6); 54 | font-family: sans-serif; } 55 | #baguetteBox-overlay .full-image:before { 56 | content: ""; 57 | display: inline-block; 58 | height: 50%; 59 | width: 1px; 60 | margin-right: -1px; } 61 | 62 | #baguetteBox-slider { 63 | position: absolute; 64 | left: 0; 65 | top: 0; 66 | height: 100%; 67 | width: 100%; 68 | white-space: nowrap; 69 | -webkit-transition: left .4s ease, -webkit-transform .4s ease; 70 | transition: left .4s ease, -webkit-transform .4s ease; 71 | transition: left .4s ease, transform .4s ease; 72 | transition: left .4s ease, transform .4s ease, -webkit-transform .4s ease, -moz-transform .4s ease; } 73 | #baguetteBox-slider.bounce-from-right { 74 | -webkit-animation: bounceFromRight .4s ease-out; 75 | animation: bounceFromRight .4s ease-out; } 76 | #baguetteBox-slider.bounce-from-left { 77 | -webkit-animation: bounceFromLeft .4s ease-out; 78 | animation: bounceFromLeft .4s ease-out; } 79 | 80 | @-webkit-keyframes bounceFromRight { 81 | 0% { 82 | margin-left: 0; } 83 | 50% { 84 | margin-left: -30px; } 85 | 100% { 86 | margin-left: 0; } } 87 | 88 | @keyframes bounceFromRight { 89 | 0% { 90 | margin-left: 0; } 91 | 50% { 92 | margin-left: -30px; } 93 | 100% { 94 | margin-left: 0; } } 95 | 96 | @-webkit-keyframes bounceFromLeft { 97 | 0% { 98 | margin-left: 0; } 99 | 50% { 100 | margin-left: 30px; } 101 | 100% { 102 | margin-left: 0; } } 103 | 104 | @keyframes bounceFromLeft { 105 | 0% { 106 | margin-left: 0; } 107 | 50% { 108 | margin-left: 30px; } 109 | 100% { 110 | margin-left: 0; } } 111 | 112 | .baguetteBox-button#next-button, .baguetteBox-button#previous-button { 113 | top: 50%; 114 | top: calc(50% - 30px); 115 | width: 44px; 116 | height: 60px; } 117 | 118 | .baguetteBox-button { 119 | position: absolute; 120 | cursor: pointer; 121 | outline: none; 122 | padding: 0; 123 | margin: 0; 124 | border: 0; 125 | -moz-border-radius: 15%; 126 | border-radius: 15%; 127 | background-color: #323232; 128 | background-color: rgba(50, 50, 50, 0.5); 129 | color: #ddd; 130 | font: 1.6em sans-serif; 131 | -webkit-transition: background-color .4s ease; 132 | transition: background-color .4s ease; } 133 | .baguetteBox-button:focus, .baguetteBox-button:hover { 134 | background-color: rgba(50, 50, 50, 0.9); } 135 | .baguetteBox-button#next-button { 136 | right: 2%; } 137 | .baguetteBox-button#previous-button { 138 | left: 2%; } 139 | .baguetteBox-button#close-button { 140 | top: 20px; 141 | right: 2%; 142 | right: calc(2% + 6px); 143 | width: 30px; 144 | height: 30px; } 145 | .baguetteBox-button svg { 146 | position: absolute; 147 | left: 0; 148 | top: 0; } 149 | 150 | /* 151 | Preloader 152 | Borrowed from http://tobiasahlin.com/spinkit/ 153 | */ 154 | .baguetteBox-spinner { 155 | width: 40px; 156 | height: 40px; 157 | display: inline-block; 158 | position: absolute; 159 | top: 50%; 160 | left: 50%; 161 | margin-top: -20px; 162 | margin-left: -20px; } 163 | 164 | .baguetteBox-double-bounce1, 165 | .baguetteBox-double-bounce2 { 166 | width: 100%; 167 | height: 100%; 168 | -moz-border-radius: 50%; 169 | border-radius: 50%; 170 | background-color: #fff; 171 | opacity: .6; 172 | position: absolute; 173 | top: 0; 174 | left: 0; 175 | -webkit-animation: bounce 2s infinite ease-in-out; 176 | animation: bounce 2s infinite ease-in-out; } 177 | 178 | .baguetteBox-double-bounce2 { 179 | -webkit-animation-delay: -1s; 180 | animation-delay: -1s; } 181 | 182 | @-webkit-keyframes bounce { 183 | 0%, 100% { 184 | -webkit-transform: scale(0); 185 | transform: scale(0); } 186 | 50% { 187 | -webkit-transform: scale(1); 188 | transform: scale(1); } } 189 | 190 | @keyframes bounce { 191 | 0%, 100% { 192 | -webkit-transform: scale(0); 193 | -moz-transform: scale(0); 194 | transform: scale(0); } 195 | 50% { 196 | -webkit-transform: scale(1); 197 | -moz-transform: scale(1); 198 | transform: scale(1); } } 199 | -------------------------------------------------------------------------------- /assets/src/styles/_external/milligram.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Milligram v1.3.0 3 | * https://milligram.github.io 4 | * 5 | * Copyright (c) 2017 CJ Patoilo 6 | * Licensed under the MIT license 7 | */ 8 | 9 | *, 10 | *:after, 11 | *:before { 12 | box-sizing: inherit; 13 | } 14 | 15 | html { 16 | box-sizing: border-box; 17 | font-size: 62.5%; 18 | } 19 | 20 | body { 21 | color: #606c76; 22 | font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; 23 | font-size: 1.6em; 24 | font-weight: 300; 25 | letter-spacing: .01em; 26 | line-height: 1.6; 27 | } 28 | 29 | blockquote { 30 | border-left: 0.3rem solid #d1d1d1; 31 | margin-left: 0; 32 | margin-right: 0; 33 | padding: 1rem 1.5rem; 34 | } 35 | 36 | blockquote *:last-child { 37 | margin-bottom: 0; 38 | } 39 | 40 | .button, 41 | button, 42 | input[type='button'], 43 | input[type='reset'], 44 | input[type='submit'] { 45 | background-color: #9b4dca; 46 | border: 0.1rem solid #9b4dca; 47 | border-radius: .4rem; 48 | color: #fff; 49 | cursor: pointer; 50 | display: inline-block; 51 | font-size: 1.1rem; 52 | font-weight: 700; 53 | height: 3.8rem; 54 | letter-spacing: .1rem; 55 | line-height: 3.8rem; 56 | padding: 0 3.0rem; 57 | text-align: center; 58 | text-decoration: none; 59 | text-transform: uppercase; 60 | white-space: nowrap; 61 | } 62 | 63 | .button:focus, .button:hover, 64 | button:focus, 65 | button:hover, 66 | input[type='button']:focus, 67 | input[type='button']:hover, 68 | input[type='reset']:focus, 69 | input[type='reset']:hover, 70 | input[type='submit']:focus, 71 | input[type='submit']:hover { 72 | background-color: #606c76; 73 | border-color: #606c76; 74 | color: #fff; 75 | outline: 0; 76 | } 77 | 78 | .button[disabled], 79 | button[disabled], 80 | input[type='button'][disabled], 81 | input[type='reset'][disabled], 82 | input[type='submit'][disabled] { 83 | cursor: default; 84 | opacity: .5; 85 | } 86 | 87 | .button[disabled]:focus, .button[disabled]:hover, 88 | button[disabled]:focus, 89 | button[disabled]:hover, 90 | input[type='button'][disabled]:focus, 91 | input[type='button'][disabled]:hover, 92 | input[type='reset'][disabled]:focus, 93 | input[type='reset'][disabled]:hover, 94 | input[type='submit'][disabled]:focus, 95 | input[type='submit'][disabled]:hover { 96 | background-color: #9b4dca; 97 | border-color: #9b4dca; 98 | } 99 | 100 | .button.button-outline, 101 | button.button-outline, 102 | input[type='button'].button-outline, 103 | input[type='reset'].button-outline, 104 | input[type='submit'].button-outline { 105 | background-color: transparent; 106 | color: #9b4dca; 107 | } 108 | 109 | .button.button-outline:focus, .button.button-outline:hover, 110 | button.button-outline:focus, 111 | button.button-outline:hover, 112 | input[type='button'].button-outline:focus, 113 | input[type='button'].button-outline:hover, 114 | input[type='reset'].button-outline:focus, 115 | input[type='reset'].button-outline:hover, 116 | input[type='submit'].button-outline:focus, 117 | input[type='submit'].button-outline:hover { 118 | background-color: transparent; 119 | border-color: #606c76; 120 | color: #606c76; 121 | } 122 | 123 | .button.button-outline[disabled]:focus, .button.button-outline[disabled]:hover, 124 | button.button-outline[disabled]:focus, 125 | button.button-outline[disabled]:hover, 126 | input[type='button'].button-outline[disabled]:focus, 127 | input[type='button'].button-outline[disabled]:hover, 128 | input[type='reset'].button-outline[disabled]:focus, 129 | input[type='reset'].button-outline[disabled]:hover, 130 | input[type='submit'].button-outline[disabled]:focus, 131 | input[type='submit'].button-outline[disabled]:hover { 132 | border-color: inherit; 133 | color: #9b4dca; 134 | } 135 | 136 | .button.button-clear, 137 | button.button-clear, 138 | input[type='button'].button-clear, 139 | input[type='reset'].button-clear, 140 | input[type='submit'].button-clear { 141 | background-color: transparent; 142 | border-color: transparent; 143 | color: #9b4dca; 144 | } 145 | 146 | .button.button-clear:focus, .button.button-clear:hover, 147 | button.button-clear:focus, 148 | button.button-clear:hover, 149 | input[type='button'].button-clear:focus, 150 | input[type='button'].button-clear:hover, 151 | input[type='reset'].button-clear:focus, 152 | input[type='reset'].button-clear:hover, 153 | input[type='submit'].button-clear:focus, 154 | input[type='submit'].button-clear:hover { 155 | background-color: transparent; 156 | border-color: transparent; 157 | color: #606c76; 158 | } 159 | 160 | .button.button-clear[disabled]:focus, .button.button-clear[disabled]:hover, 161 | button.button-clear[disabled]:focus, 162 | button.button-clear[disabled]:hover, 163 | input[type='button'].button-clear[disabled]:focus, 164 | input[type='button'].button-clear[disabled]:hover, 165 | input[type='reset'].button-clear[disabled]:focus, 166 | input[type='reset'].button-clear[disabled]:hover, 167 | input[type='submit'].button-clear[disabled]:focus, 168 | input[type='submit'].button-clear[disabled]:hover { 169 | color: #9b4dca; 170 | } 171 | 172 | code { 173 | background: #f4f5f6; 174 | border-radius: .4rem; 175 | font-size: 86%; 176 | margin: 0 .2rem; 177 | padding: .2rem .5rem; 178 | white-space: nowrap; 179 | } 180 | 181 | pre { 182 | background: #f4f5f6; 183 | border-left: 0.3rem solid #9b4dca; 184 | overflow-y: hidden; 185 | } 186 | 187 | pre > code { 188 | border-radius: 0; 189 | display: block; 190 | padding: 1rem 1.5rem; 191 | white-space: pre; 192 | } 193 | 194 | hr { 195 | border: 0; 196 | border-top: 0.1rem solid #f4f5f6; 197 | margin: 3.0rem 0; 198 | } 199 | 200 | input[type='email'], 201 | input[type='number'], 202 | input[type='password'], 203 | input[type='search'], 204 | input[type='tel'], 205 | input[type='text'], 206 | input[type='url'], 207 | textarea, 208 | select { 209 | -webkit-appearance: none; 210 | -moz-appearance: none; 211 | appearance: none; 212 | background-color: transparent; 213 | border: 0.1rem solid #d1d1d1; 214 | border-radius: .4rem; 215 | box-shadow: none; 216 | box-sizing: inherit; 217 | height: 3.8rem; 218 | padding: .6rem 1.0rem; 219 | width: 100%; 220 | } 221 | 222 | input[type='email']:focus, 223 | input[type='number']:focus, 224 | input[type='password']:focus, 225 | input[type='search']:focus, 226 | input[type='tel']:focus, 227 | input[type='text']:focus, 228 | input[type='url']:focus, 229 | textarea:focus, 230 | select:focus { 231 | border-color: #9b4dca; 232 | outline: 0; 233 | } 234 | 235 | select { 236 | background: url('data:image/svg+xml;utf8,') center right no-repeat; 237 | padding-right: 3.0rem; 238 | } 239 | 240 | select:focus { 241 | background-image: url('data:image/svg+xml;utf8,'); 242 | } 243 | 244 | textarea { 245 | min-height: 6.5rem; 246 | } 247 | 248 | label, 249 | legend { 250 | display: block; 251 | font-size: 1.6rem; 252 | font-weight: 700; 253 | margin-bottom: .5rem; 254 | } 255 | 256 | fieldset { 257 | border-width: 0; 258 | padding: 0; 259 | } 260 | 261 | input[type='checkbox'], 262 | input[type='radio'] { 263 | display: inline; 264 | } 265 | 266 | .label-inline { 267 | display: inline-block; 268 | font-weight: normal; 269 | margin-left: .5rem; 270 | } 271 | 272 | .container { 273 | margin: 0 auto; 274 | max-width: 112.0rem; 275 | padding: 0 2.0rem; 276 | position: relative; 277 | width: 100%; 278 | } 279 | 280 | .row { 281 | display: flex; 282 | flex-direction: column; 283 | padding: 0; 284 | width: 100%; 285 | } 286 | 287 | .row.row-no-padding { 288 | padding: 0; 289 | } 290 | 291 | .row.row-no-padding > .column { 292 | padding: 0; 293 | } 294 | 295 | .row.row-wrap { 296 | flex-wrap: wrap; 297 | } 298 | 299 | .row.row-top { 300 | align-items: flex-start; 301 | } 302 | 303 | .row.row-bottom { 304 | align-items: flex-end; 305 | } 306 | 307 | .row.row-center { 308 | align-items: center; 309 | } 310 | 311 | .row.row-stretch { 312 | align-items: stretch; 313 | } 314 | 315 | .row.row-baseline { 316 | align-items: baseline; 317 | } 318 | 319 | .row .column { 320 | display: block; 321 | flex: 1 1 auto; 322 | margin-left: 0; 323 | max-width: 100%; 324 | width: 100%; 325 | } 326 | 327 | .row .column.column-offset-10 { 328 | margin-left: 10%; 329 | } 330 | 331 | .row .column.column-offset-20 { 332 | margin-left: 20%; 333 | } 334 | 335 | .row .column.column-offset-25 { 336 | margin-left: 25%; 337 | } 338 | 339 | .row .column.column-offset-33, .row .column.column-offset-34 { 340 | margin-left: 33.3333%; 341 | } 342 | 343 | .row .column.column-offset-50 { 344 | margin-left: 50%; 345 | } 346 | 347 | .row .column.column-offset-66, .row .column.column-offset-67 { 348 | margin-left: 66.6666%; 349 | } 350 | 351 | .row .column.column-offset-75 { 352 | margin-left: 75%; 353 | } 354 | 355 | .row .column.column-offset-80 { 356 | margin-left: 80%; 357 | } 358 | 359 | .row .column.column-offset-90 { 360 | margin-left: 90%; 361 | } 362 | 363 | .row .column.column-10 { 364 | flex: 0 0 10%; 365 | max-width: 10%; 366 | } 367 | 368 | .row .column.column-20 { 369 | flex: 0 0 20%; 370 | max-width: 20%; 371 | } 372 | 373 | .row .column.column-25 { 374 | flex: 0 0 25%; 375 | max-width: 25%; 376 | } 377 | 378 | .row .column.column-33, .row .column.column-34 { 379 | flex: 0 0 33.3333%; 380 | max-width: 33.3333%; 381 | } 382 | 383 | .row .column.column-40 { 384 | flex: 0 0 40%; 385 | max-width: 40%; 386 | } 387 | 388 | .row .column.column-50 { 389 | flex: 0 0 50%; 390 | max-width: 50%; 391 | } 392 | 393 | .row .column.column-60 { 394 | flex: 0 0 60%; 395 | max-width: 60%; 396 | } 397 | 398 | .row .column.column-66, .row .column.column-67 { 399 | flex: 0 0 66.6666%; 400 | max-width: 66.6666%; 401 | } 402 | 403 | .row .column.column-75 { 404 | flex: 0 0 75%; 405 | max-width: 75%; 406 | } 407 | 408 | .row .column.column-80 { 409 | flex: 0 0 80%; 410 | max-width: 80%; 411 | } 412 | 413 | .row .column.column-90 { 414 | flex: 0 0 90%; 415 | max-width: 90%; 416 | } 417 | 418 | .row .column .column-top { 419 | align-self: flex-start; 420 | } 421 | 422 | .row .column .column-bottom { 423 | align-self: flex-end; 424 | } 425 | 426 | .row .column .column-center { 427 | -ms-grid-row-align: center; 428 | align-self: center; 429 | } 430 | 431 | @media (min-width: 40rem) { 432 | .row { 433 | flex-direction: row; 434 | margin-left: -1.0rem; 435 | width: calc(100% + 2.0rem); 436 | } 437 | .row .column { 438 | margin-bottom: inherit; 439 | padding: 0 1.0rem; 440 | } 441 | } 442 | 443 | a { 444 | color: #9b4dca; 445 | text-decoration: none; 446 | } 447 | 448 | a:focus, a:hover { 449 | color: #606c76; 450 | } 451 | 452 | dl, 453 | ol, 454 | ul { 455 | list-style: none; 456 | margin-top: 0; 457 | padding-left: 0; 458 | } 459 | 460 | dl dl, 461 | dl ol, 462 | dl ul, 463 | ol dl, 464 | ol ol, 465 | ol ul, 466 | ul dl, 467 | ul ol, 468 | ul ul { 469 | font-size: 90%; 470 | margin: 1.5rem 0 1.5rem 3.0rem; 471 | } 472 | 473 | ol { 474 | list-style: decimal inside; 475 | } 476 | 477 | ul { 478 | list-style: circle inside; 479 | } 480 | 481 | .button, 482 | button, 483 | dd, 484 | dt, 485 | li { 486 | margin-bottom: 1.0rem; 487 | } 488 | 489 | fieldset, 490 | input, 491 | select, 492 | textarea { 493 | margin-bottom: 1.5rem; 494 | } 495 | 496 | blockquote, 497 | dl, 498 | figure, 499 | form, 500 | ol, 501 | p, 502 | pre, 503 | table, 504 | ul { 505 | margin-bottom: 2.5rem; 506 | } 507 | 508 | table { 509 | border-spacing: 0; 510 | width: 100%; 511 | } 512 | 513 | td, 514 | th { 515 | border-bottom: 0.1rem solid #e1e1e1; 516 | padding: 1.2rem 1.5rem; 517 | text-align: left; 518 | } 519 | 520 | td:first-child, 521 | th:first-child { 522 | padding-left: 0; 523 | } 524 | 525 | td:last-child, 526 | th:last-child { 527 | padding-right: 0; 528 | } 529 | 530 | b, 531 | strong { 532 | font-weight: bold; 533 | } 534 | 535 | p { 536 | margin-top: 0; 537 | } 538 | 539 | h1, 540 | h2, 541 | h3, 542 | h4, 543 | h5, 544 | h6 { 545 | font-weight: 300; 546 | letter-spacing: -.1rem; 547 | margin-bottom: 2.0rem; 548 | margin-top: 0; 549 | } 550 | 551 | h1 { 552 | font-size: 4.6rem; 553 | line-height: 1.2; 554 | } 555 | 556 | h2 { 557 | font-size: 3.6rem; 558 | line-height: 1.25; 559 | } 560 | 561 | h3 { 562 | font-size: 2.8rem; 563 | line-height: 1.3; 564 | } 565 | 566 | h4 { 567 | font-size: 2.2rem; 568 | letter-spacing: -.08rem; 569 | line-height: 1.35; 570 | } 571 | 572 | h5 { 573 | font-size: 1.8rem; 574 | letter-spacing: -.05rem; 575 | line-height: 1.5; 576 | } 577 | 578 | h6 { 579 | font-size: 1.6rem; 580 | letter-spacing: 0; 581 | line-height: 1.4; 582 | } 583 | 584 | img { 585 | max-width: 100%; 586 | } 587 | 588 | .clearfix:after { 589 | clear: both; 590 | content: ' '; 591 | display: table; 592 | } 593 | 594 | .float-left { 595 | float: left; 596 | } 597 | 598 | .float-right { 599 | float: right; 600 | } 601 | 602 | /*# sourceMappingURL=milligram.css.map */ -------------------------------------------------------------------------------- /assets/src/styles/_external/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Correct the font size and margin on `h1` elements within `section` and 29 | * `article` contexts in Chrome, Firefox, and Safari. 30 | */ 31 | 32 | h1 { 33 | font-size: 2em; 34 | margin: 0.67em 0; 35 | } 36 | 37 | /* Grouping content 38 | ========================================================================== */ 39 | 40 | /** 41 | * 1. Add the correct box sizing in Firefox. 42 | * 2. Show the overflow in Edge and IE. 43 | */ 44 | 45 | hr { 46 | box-sizing: content-box; /* 1 */ 47 | height: 0; /* 1 */ 48 | overflow: visible; /* 2 */ 49 | } 50 | 51 | /** 52 | * 1. Correct the inheritance and scaling of font size in all browsers. 53 | * 2. Correct the odd `em` font sizing in all browsers. 54 | */ 55 | 56 | pre { 57 | font-family: monospace, monospace; /* 1 */ 58 | font-size: 1em; /* 2 */ 59 | } 60 | 61 | /* Text-level semantics 62 | ========================================================================== */ 63 | 64 | /** 65 | * Remove the gray background on active links in IE 10. 66 | */ 67 | 68 | a { 69 | background-color: transparent; 70 | } 71 | 72 | /** 73 | * 1. Remove the bottom border in Chrome 57- 74 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 75 | */ 76 | 77 | abbr[title] { 78 | border-bottom: none; /* 1 */ 79 | text-decoration: underline; /* 2 */ 80 | text-decoration: underline dotted; /* 2 */ 81 | } 82 | 83 | /** 84 | * Add the correct font weight in Chrome, Edge, and Safari. 85 | */ 86 | 87 | b, 88 | strong { 89 | font-weight: bolder; 90 | } 91 | 92 | /** 93 | * 1. Correct the inheritance and scaling of font size in all browsers. 94 | * 2. Correct the odd `em` font sizing in all browsers. 95 | */ 96 | 97 | code, 98 | kbd, 99 | samp { 100 | font-family: monospace, monospace; /* 1 */ 101 | font-size: 1em; /* 2 */ 102 | } 103 | 104 | /** 105 | * Add the correct font size in all browsers. 106 | */ 107 | 108 | small { 109 | font-size: 80%; 110 | } 111 | 112 | /** 113 | * Prevent `sub` and `sup` elements from affecting the line height in 114 | * all browsers. 115 | */ 116 | 117 | sub, 118 | sup { 119 | font-size: 75%; 120 | line-height: 0; 121 | position: relative; 122 | vertical-align: baseline; 123 | } 124 | 125 | sub { 126 | bottom: -0.25em; 127 | } 128 | 129 | sup { 130 | top: -0.5em; 131 | } 132 | 133 | /* Embedded content 134 | ========================================================================== */ 135 | 136 | /** 137 | * Remove the border on images inside links in IE 10. 138 | */ 139 | 140 | img { 141 | border-style: none; 142 | } 143 | 144 | /* Forms 145 | ========================================================================== */ 146 | 147 | /** 148 | * 1. Change the font styles in all browsers. 149 | * 2. Remove the margin in Firefox and Safari. 150 | */ 151 | 152 | button, 153 | input, 154 | optgroup, 155 | select, 156 | textarea { 157 | font-family: inherit; /* 1 */ 158 | font-size: 100%; /* 1 */ 159 | line-height: 1.15; /* 1 */ 160 | margin: 0; /* 2 */ 161 | } 162 | 163 | /** 164 | * Show the overflow in IE. 165 | * 1. Show the overflow in Edge. 166 | */ 167 | 168 | button, 169 | input { /* 1 */ 170 | overflow: visible; 171 | } 172 | 173 | /** 174 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 175 | * 1. Remove the inheritance of text transform in Firefox. 176 | */ 177 | 178 | button, 179 | select { /* 1 */ 180 | text-transform: none; 181 | } 182 | 183 | /** 184 | * Correct the inability to style clickable types in iOS and Safari. 185 | */ 186 | 187 | button, 188 | [type="button"], 189 | [type="reset"], 190 | [type="submit"] { 191 | -webkit-appearance: button; 192 | } 193 | 194 | /** 195 | * Remove the inner border and padding in Firefox. 196 | */ 197 | 198 | button::-moz-focus-inner, 199 | [type="button"]::-moz-focus-inner, 200 | [type="reset"]::-moz-focus-inner, 201 | [type="submit"]::-moz-focus-inner { 202 | border-style: none; 203 | padding: 0; 204 | } 205 | 206 | /** 207 | * Restore the focus styles unset by the previous rule. 208 | */ 209 | 210 | button:-moz-focusring, 211 | [type="button"]:-moz-focusring, 212 | [type="reset"]:-moz-focusring, 213 | [type="submit"]:-moz-focusring { 214 | outline: 1px dotted ButtonText; 215 | } 216 | 217 | /** 218 | * Correct the padding in Firefox. 219 | */ 220 | 221 | fieldset { 222 | padding: 0.35em 0.75em 0.625em; 223 | } 224 | 225 | /** 226 | * 1. Correct the text wrapping in Edge and IE. 227 | * 2. Correct the color inheritance from `fieldset` elements in IE. 228 | * 3. Remove the padding so developers are not caught out when they zero out 229 | * `fieldset` elements in all browsers. 230 | */ 231 | 232 | legend { 233 | box-sizing: border-box; /* 1 */ 234 | color: inherit; /* 2 */ 235 | display: table; /* 1 */ 236 | max-width: 100%; /* 1 */ 237 | padding: 0; /* 3 */ 238 | white-space: normal; /* 1 */ 239 | } 240 | 241 | /** 242 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 243 | */ 244 | 245 | progress { 246 | vertical-align: baseline; 247 | } 248 | 249 | /** 250 | * Remove the default vertical scrollbar in IE 10+. 251 | */ 252 | 253 | textarea { 254 | overflow: auto; 255 | } 256 | 257 | /** 258 | * 1. Add the correct box sizing in IE 10. 259 | * 2. Remove the padding in IE 10. 260 | */ 261 | 262 | [type="checkbox"], 263 | [type="radio"] { 264 | box-sizing: border-box; /* 1 */ 265 | padding: 0; /* 2 */ 266 | } 267 | 268 | /** 269 | * Correct the cursor style of increment and decrement buttons in Chrome. 270 | */ 271 | 272 | [type="number"]::-webkit-inner-spin-button, 273 | [type="number"]::-webkit-outer-spin-button { 274 | height: auto; 275 | } 276 | 277 | /** 278 | * 1. Correct the odd appearance in Chrome and Safari. 279 | * 2. Correct the outline style in Safari. 280 | */ 281 | 282 | [type="search"] { 283 | -webkit-appearance: textfield; /* 1 */ 284 | outline-offset: -2px; /* 2 */ 285 | } 286 | 287 | /** 288 | * Remove the inner padding in Chrome and Safari on macOS. 289 | */ 290 | 291 | [type="search"]::-webkit-search-decoration { 292 | -webkit-appearance: none; 293 | } 294 | 295 | /** 296 | * 1. Correct the inability to style clickable types in iOS and Safari. 297 | * 2. Change font properties to `inherit` in Safari. 298 | */ 299 | 300 | ::-webkit-file-upload-button { 301 | -webkit-appearance: button; /* 1 */ 302 | font: inherit; /* 2 */ 303 | } 304 | 305 | /* Interactive 306 | ========================================================================== */ 307 | 308 | /* 309 | * Add the correct display in Edge, IE 10+, and Firefox. 310 | */ 311 | 312 | details { 313 | display: block; 314 | } 315 | 316 | /* 317 | * Add the correct display in all browsers. 318 | */ 319 | 320 | summary { 321 | display: list-item; 322 | } 323 | 324 | /* Misc 325 | ========================================================================== */ 326 | 327 | /** 328 | * Add the correct display in IE 10+. 329 | */ 330 | 331 | template { 332 | display: none; 333 | } 334 | 335 | /** 336 | * Add the correct display in IE 10. 337 | */ 338 | 339 | [hidden] { 340 | display: none; 341 | } 342 | -------------------------------------------------------------------------------- /assets/src/styles/_settings.scss: -------------------------------------------------------------------------------- 1 | $breakpoint: 800px; 2 | $itemMargin: 2.5rem; 3 | 4 | $color-brilliant-azure: #39f; 5 | $color-bara-red: #f0506e; 6 | $color-black: #000; 7 | $color-pale-grey: #fefefe; 8 | $color-silver: #c0c0c0; 9 | $color-zhen-zhu-bai-pearl: #f8f8f8; 10 | 11 | $base-background-color: $color-pale-grey; 12 | 13 | $navbar-background-color: $color-zhen-zhu-bai-pearl; 14 | $navbar-height: 5rem; 15 | $navbar-text-color: $color-black; 16 | 17 | $links-color: $color-brilliant-azure; 18 | -------------------------------------------------------------------------------- /assets/src/styles/styles.scss: -------------------------------------------------------------------------------- 1 | @import "chroma_friendly"; 2 | @import "settings"; 3 | @import "_components/base"; 4 | @import "_components/content"; 5 | @import "_components/elements"; 6 | @import "_components/footer"; 7 | @import "_components/homepage"; 8 | @import "_components/navbar"; 9 | -------------------------------------------------------------------------------- /exampleSite/config.toml: -------------------------------------------------------------------------------- 1 | baseURL = "https://example.com" 2 | defaultContentLanguage = "en" 3 | disqusShortname = "test" 4 | enableEmoji = true 5 | enableRobotsTXT = true 6 | googleAnalytics = "" 7 | languageCode = "en-us" 8 | pygmentsCodeFences = true 9 | pygmentsStyle = "native" 10 | pygmentsUseClasses = true 11 | theme = "simplicity" 12 | title = "Simplicity - Hugo theme" 13 | [author] 14 | gravatarEmail = "test@example.com" 15 | homepageText = "Simplicity" 16 | name = "Przemysław `eshlox` Kołodziejczyk" 17 | rss = "/posts/index.xml" 18 | [imaging] 19 | anchor = "smart" 20 | resampleFilter = "box" 21 | quality = 75 22 | [[menu.pages]] 23 | name = "Projects" 24 | weight = -100 25 | identifier = "projects" 26 | url = "/projects/" 27 | [[menu.pages]] 28 | name = "Photos" 29 | weight = -90 30 | identifier = "photos" 31 | url = "/photos/" 32 | [outputs] 33 | home = ["HTML"] 34 | page = ["HTML"] 35 | section = ["HTML", "RSS"] 36 | taxonomy = ["HTML", "RSS"] 37 | taxonomyTerm = ["HTML"] 38 | [params] 39 | adsenseClient = '' 40 | adsenseSlot = '' 41 | description = "A blog about everything." 42 | licence = "[Some Rights Reserved](http://creativecommons.org/licenses/by-sa/4.0/)." 43 | displayPostLanguage = true 44 | [permalinks] 45 | posts = "/:year/:month/:day/:slug/" 46 | [pygmentsOptions] 47 | linenos = false 48 | -------------------------------------------------------------------------------- /exampleSite/content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Homepage 3 | language: en 4 | slug: / 5 | --- 6 | 7 | # Simplicity, Hugo theme. 8 | 9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 10 | 11 | [Posts](/posts/) • [Categories](/categories/) • [Tags](/tags/) 12 | 13 | [Photos](/photos/) • [Projects](/projects/) 14 | -------------------------------------------------------------------------------- /exampleSite/content/categories/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Categories 3 | language: en 4 | slug: /categories/ 5 | --- 6 | -------------------------------------------------------------------------------- /exampleSite/content/media/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Media Folder 3 | --- 4 | -------------------------------------------------------------------------------- /exampleSite/content/media/image-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eshlox/simplicity/8696b3b61946d89bb0cd1fc1920940544f1758e9/exampleSite/content/media/image-1.jpg -------------------------------------------------------------------------------- /exampleSite/content/media/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eshlox/simplicity/8696b3b61946d89bb0cd1fc1920940544f1758e9/exampleSite/content/media/video.mp4 -------------------------------------------------------------------------------- /exampleSite/content/photos.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Photos 3 | language: en 4 | slug: photos 5 | --- 6 | 7 | {{< image src="media/image-1.jpg" title="Photo by Ales Krivec on Unsplash" lightbox="true" >}} 8 | 9 | {{< image src="media/image-1.jpg" title="Photo by Ales Krivec on Unsplash" >}} 10 | -------------------------------------------------------------------------------- /exampleSite/content/posts/2014/goisforlovers.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "(Hu)go Template Primer" 3 | description = "" 4 | tags = [ 5 | "go", 6 | "golang", 7 | "templates", 8 | "themes", 9 | "development", 10 | ] 11 | date = "2014-04-02" 12 | categories = [ 13 | "Development", 14 | "golang", 15 | ] 16 | menu = "main" 17 | +++ 18 | 19 | Hugo uses the excellent [go][] [html/template][gohtmltemplate] library for 20 | its template engine. It is an extremely lightweight engine that provides a very 21 | small amount of logic. In our experience that it is just the right amount of 22 | logic to be able to create a good static website. If you have used other 23 | template systems from different languages or frameworks you will find a lot of 24 | similarities in go templates. 25 | 26 | This document is a brief primer on using go templates. The [go docs][gohtmltemplate] 27 | provide more details. 28 | 29 | ## Introduction to Go Templates 30 | 31 | Go templates provide an extremely simple template language. It adheres to the 32 | belief that only the most basic of logic belongs in the template or view layer. 33 | One consequence of this simplicity is that go templates parse very quickly. 34 | 35 | A unique characteristic of go templates is they are content aware. Variables and 36 | content will be sanitized depending on the context of where they are used. More 37 | details can be found in the [go docs][gohtmltemplate]. 38 | 39 | ## Basic Syntax 40 | 41 | Go lang templates are html files with the addition of variables and 42 | functions. 43 | 44 | **Go variables and functions are accessible within {{ }}** 45 | 46 | Accessing a predefined variable "foo": 47 | 48 | {{ foo }} 49 | 50 | **Parameters are separated using spaces** 51 | 52 | Calling the add function with input of 1, 2: 53 | 54 | {{ add 1 2 }} 55 | 56 | **Methods and fields are accessed via dot notation** 57 | 58 | Accessing the Page Parameter "bar" 59 | 60 | {{ .Params.bar }} 61 | 62 | **Parentheses can be used to group items together** 63 | 64 | {{ if or (isset .Params "alt") (isset .Params "caption") }} Caption {{ end }} 65 | 66 | 67 | ## Variables 68 | 69 | Each go template has a struct (object) made available to it. In hugo each 70 | template is passed either a page or a node struct depending on which type of 71 | page you are rendering. More details are available on the 72 | [variables](/layout/variables) page. 73 | 74 | A variable is accessed by referencing the variable name. 75 | 76 | {{ .Title }} 77 | 78 | Variables can also be defined and referenced. 79 | 80 | {{ $address := "123 Main St."}} 81 | {{ $address }} 82 | 83 | 84 | ## Functions 85 | 86 | Go template ship with a few functions which provide basic functionality. The go 87 | template system also provides a mechanism for applications to extend the 88 | available functions with their own. [Hugo template 89 | functions](/layout/functions) provide some additional functionality we believe 90 | are useful for building websites. Functions are called by using their name 91 | followed by the required parameters separated by spaces. Template 92 | functions cannot be added without recompiling hugo. 93 | 94 | **Example:** 95 | 96 | {{ add 1 2 }} 97 | 98 | ## Includes 99 | 100 | When including another template you will pass to it the data it will be 101 | able to access. To pass along the current context please remember to 102 | include a trailing dot. The templates location will always be starting at 103 | the /layout/ directory within Hugo. 104 | 105 | **Example:** 106 | 107 | {{ template "chrome/header.html" . }} 108 | 109 | 110 | ## Logic 111 | 112 | Go templates provide the most basic iteration and conditional logic. 113 | 114 | ### Iteration 115 | 116 | Just like in go, the go templates make heavy use of range to iterate over 117 | a map, array or slice. The following are different examples of how to use 118 | range. 119 | 120 | **Example 1: Using Context** 121 | 122 | {{ range array }} 123 | {{ . }} 124 | {{ end }} 125 | 126 | **Example 2: Declaring value variable name** 127 | 128 | {{range $element := array}} 129 | {{ $element }} 130 | {{ end }} 131 | 132 | **Example 2: Declaring key and value variable name** 133 | 134 | {{range $index, $element := array}} 135 | {{ $index }} 136 | {{ $element }} 137 | {{ end }} 138 | 139 | ### Conditionals 140 | 141 | If, else, with, or, & and provide the framework for handling conditional 142 | logic in Go Templates. Like range, each statement is closed with `end`. 143 | 144 | 145 | Go Templates treat the following values as false: 146 | 147 | * false 148 | * 0 149 | * any array, slice, map, or string of length zero 150 | 151 | **Example 1: If** 152 | 153 | {{ if isset .Params "title" }}

{{ index .Params "title" }}

{{ end }} 154 | 155 | **Example 2: If -> Else** 156 | 157 | {{ if isset .Params "alt" }} 158 | {{ index .Params "alt" }} 159 | {{else}} 160 | {{ index .Params "caption" }} 161 | {{ end }} 162 | 163 | **Example 3: And & Or** 164 | 165 | {{ if and (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")}} 166 | 167 | **Example 4: With** 168 | 169 | An alternative way of writing "if" and then referencing the same value 170 | is to use "with" instead. With rebinds the context `.` within its scope, 171 | and skips the block if the variable is absent. 172 | 173 | The first example above could be simplified as: 174 | 175 | {{ with .Params.title }}

{{ . }}

{{ end }} 176 | 177 | **Example 5: If -> Else If** 178 | 179 | {{ if isset .Params "alt" }} 180 | {{ index .Params "alt" }} 181 | {{ else if isset .Params "caption" }} 182 | {{ index .Params "caption" }} 183 | {{ end }} 184 | 185 | ## Pipes 186 | 187 | One of the most powerful components of go templates is the ability to 188 | stack actions one after another. This is done by using pipes. Borrowed 189 | from unix pipes, the concept is simple, each pipeline's output becomes the 190 | input of the following pipe. 191 | 192 | Because of the very simple syntax of go templates, the pipe is essential 193 | to being able to chain together function calls. One limitation of the 194 | pipes is that they only can work with a single value and that value 195 | becomes the last parameter of the next pipeline. 196 | 197 | A few simple examples should help convey how to use the pipe. 198 | 199 | **Example 1 :** 200 | 201 | {{ if eq 1 1 }} Same {{ end }} 202 | 203 | is the same as 204 | 205 | {{ eq 1 1 | if }} Same {{ end }} 206 | 207 | It does look odd to place the if at the end, but it does provide a good 208 | illustration of how to use the pipes. 209 | 210 | **Example 2 :** 211 | 212 | {{ index .Params "disqus_url" | html }} 213 | 214 | Access the page parameter called "disqus_url" and escape the HTML. 215 | 216 | **Example 3 :** 217 | 218 | {{ if or (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")}} 219 | Stuff Here 220 | {{ end }} 221 | 222 | Could be rewritten as 223 | 224 | {{ isset .Params "caption" | or isset .Params "title" | or isset .Params "attr" | if }} 225 | Stuff Here 226 | {{ end }} 227 | 228 | 229 | ## Context (aka. the dot) 230 | 231 | The most easily overlooked concept to understand about go templates is that {{ . }} 232 | always refers to the current context. In the top level of your template this 233 | will be the data set made available to it. Inside of a iteration it will have 234 | the value of the current item. When inside of a loop the context has changed. . 235 | will no longer refer to the data available to the entire page. If you need to 236 | access this from within the loop you will likely want to set it to a variable 237 | instead of depending on the context. 238 | 239 | **Example:** 240 | 241 | {{ $title := .Site.Title }} 242 | {{ range .Params.tags }} 243 |
  • {{ . }} - {{ $title }}
  • 244 | {{ end }} 245 | 246 | Notice how once we have entered the loop the value of {{ . }} has changed. We 247 | have defined a variable outside of the loop so we have access to it from within 248 | the loop. 249 | 250 | # Hugo Parameters 251 | 252 | Hugo provides the option of passing values to the template language 253 | through the site configuration (for sitewide values), or through the meta 254 | data of each specific piece of content. You can define any values of any 255 | type (supported by your front matter/config format) and use them however 256 | you want to inside of your templates. 257 | 258 | 259 | ## Using Content (page) Parameters 260 | 261 | In each piece of content you can provide variables to be used by the 262 | templates. This happens in the [front matter](/content/front-matter). 263 | 264 | An example of this is used in this documentation site. Most of the pages 265 | benefit from having the table of contents provided. Sometimes the TOC just 266 | doesn't make a lot of sense. We've defined a variable in our front matter 267 | of some pages to turn off the TOC from being displayed. 268 | 269 | Here is the example front matter: 270 | 271 | ``` 272 | --- 273 | title: "Permalinks" 274 | date: "2013-11-18" 275 | aliases: 276 | - "/doc/permalinks/" 277 | groups: ["extras"] 278 | groups_weight: 30 279 | notoc: true 280 | --- 281 | ``` 282 | 283 | Here is the corresponding code inside of the template: 284 | 285 | {{ if not .Params.notoc }} 286 |
    287 | {{ .TableOfContents }} 288 |
    289 | {{ end }} 290 | 291 | 292 | 293 | ## Using Site (config) Parameters 294 | In your top-level configuration file (eg, `config.yaml`) you can define site 295 | parameters, which are values which will be available to you in chrome. 296 | 297 | For instance, you might declare: 298 | 299 | ```yaml 300 | params: 301 | CopyrightHTML: "Copyright © 2013 John Doe. All Rights Reserved." 302 | TwitterUser: "spf13" 303 | SidebarRecentLimit: 5 304 | ``` 305 | 306 | Within a footer layout, you might then declare a `