├── .gitignore ├── src ├── tslint.json └── sct.ts ├── tsconfig.json ├── demo ├── assets │ ├── 2.jpg │ ├── 6.jpg │ ├── 8.jpg │ ├── demo.gif │ ├── desktop.mp4 │ ├── mobile.mp4 │ ├── sbt-blink.gif │ ├── sbt-animate.gif │ └── sbt-progress.gif ├── demo.html ├── demo.js ├── demo.pcss └── demo.css ├── .editorconfig ├── LICENSE ├── package.json ├── README.md └── dist └── sct.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea/ 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended" 3 | } 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions" : { 3 | "target": "es5" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /demo/assets/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/2.jpg -------------------------------------------------------------------------------- /demo/assets/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/6.jpg -------------------------------------------------------------------------------- /demo/assets/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/8.jpg -------------------------------------------------------------------------------- /demo/assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/demo.gif -------------------------------------------------------------------------------- /demo/assets/desktop.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/desktop.mp4 -------------------------------------------------------------------------------- /demo/assets/mobile.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/mobile.mp4 -------------------------------------------------------------------------------- /demo/assets/sbt-blink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/sbt-blink.gif -------------------------------------------------------------------------------- /demo/assets/sbt-animate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/sbt-animate.gif -------------------------------------------------------------------------------- /demo/assets/sbt-progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neSpecc/safari-beauty-toolbar/HEAD/demo/assets/sbt-progress.gif -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = false 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Petr Savchenko 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "safari-beauty-toolbar", 3 | "version": "1.0.3", 4 | "description": "Make the Safari Toolbar more consistent with your brand colors", 5 | "repository": "git+https://github.com/neSpecc/safari-beauty-toolbar.git", 6 | "bugs": { 7 | "url": "https://github.com/neSpecc/safari-beauty-toolbar/issues" 8 | }, 9 | "homepage": "https://ifmo.su/beauty-toolbar", 10 | "main": "dist/sct.min.js", 11 | "scripts": { 12 | "css": "postcss ./demo/demo.pcss --no-map -u postcss-cssnext postcss-nested -o ./demo/demo.css --watch", 13 | "build": "webpack -p --entry=./src/sct.ts --module-bind ts=ts-loader --output=./dist/sct.min.js --output-library-target=umd --output-library=SBToolbar" 14 | }, 15 | "keywords": [ 16 | "codex", 17 | "safari", 18 | "toolbar", 19 | "branding" 20 | ], 21 | "author": "Petr Savchenko", 22 | "license": "MIT", 23 | "devDependencies": { 24 | "postcss-cli": "^5.0.0", 25 | "postcss-cssnext": "^3.1.0", 26 | "postcss-nested": "^3.0.0", 27 | "ts-loader": "^4.4.2", 28 | "tslint": "^5.9.1", 29 | "typescript": "^2.8.1", 30 | "webpack": "^4.16.3", 31 | "webpack-cli": "^3.1.0" 32 | }, 33 | "private": false 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Safari Beauty Toolbar 2 | 3 | Tiny JavaScript module that makes the Safari Toolbar colorful. It uses native toolbar's transparency so there are two restrictions: 4 | 5 | - Works only at the Safari on MacOS or iOS 6 | - Displays after some scroll offset 7 | 8 | ## Installation 9 | 10 | Install module via Yarn, then import to the Code. 11 | 12 | ```shell 13 | yarn add safari-beauty-toolbar 14 | ``` 15 | 16 | or with NPM 17 | 18 | ```shell 19 | npm i safari-beauty-toolbar --save 20 | ``` 21 | 22 | You can also download [dist/sct.min.js](https://github.com/neSpecc/safari-beauty-toolbar/blob/master/dist/sct.min.js) and manually connect it with your project. 23 | 24 | ```js 25 | import SBToolbar from 'safari-beauty-toolbar'; 26 | ``` 27 | 28 | ## Usage 29 | 30 | Basic usage is quite simple: just pass your brand color to the constructor. 31 | 32 | ```js 33 | const toolbarColor = new SBToolbar({ 34 | color: "red" 35 | }); 36 | ``` 37 | 38 | param | type | default | description 39 | -- | -- | -- | -- 40 | `color` | _string_ | - | Toolbar color. **Required** 41 | 42 | This makes the Toolbar colorful. Try to reload the page and scroll it down. 43 | 44 | > Note. Because of transparency value of the Toolbar, you probably should pass little more saturated color than the usual brand's color. 45 | 46 | > Note. Place the initialization code at the bottom of ``-tag or call after document-ready event. 47 | 48 | ![](demo/assets/demo.gif) 49 | 50 | ## Public methods 51 | 52 | There are some additional methods that your can find useful in some cases. 53 | 54 | - [Blinking](#blinking) 55 | - [Animation](#animation) 56 | - [Progress](#progress) 57 | - [Reinit](#reinit) 58 | - [Stop Blinking](#stop-blinking) 59 | - [Stop Animation](#stop-animation) 60 | - [Stop All Effects](#stop-all-effects) 61 | - [Destroy](#destroy) 62 | 63 | 64 | ### Blinking 65 | 66 | ![](demo/assets/sbt-blink.gif) 67 | 68 | ```js 69 | blink({interval, transitionSpeed}) 70 | 71 | ``` 72 | 73 | Parameters passed as the destructuring assignment. 74 | 75 | param | type | default | description 76 | -- | -- | -- | -- 77 | `interval` | _number_ | 400 | time between transparent and opaque color in ms 78 | `transitionSpeed` | _number_ | 500 | speed of transparency changing in ms 79 | 80 | Usage example 81 | 82 | ```js 83 | toolbarColor.blink({ 84 | interval: 300, 85 | transitionSpeed: 1000 86 | }); 87 | ``` 88 | 89 | ### Animation 90 | 91 | ![](demo/assets/sbt-animate.gif) 92 | 93 | ```js 94 | animate({colors, speed}) 95 | 96 | ``` 97 | 98 | Parameters passed as the destructuring assignment. 99 | 100 | param | type | default | description 101 | -- | -- | -- | -- 102 | `colors` | _string[]_ | - | list of colors to change. **Required**. 103 | `speed` | _number_ | 800 | speed of color transition in ms 104 | 105 | Usage example 106 | 107 | ```js 108 | toolbarColor.animate({ 109 | colors: ["#ff0a8a", "blue", "#61ffa7", "yellow"], 110 | speed: 600 111 | }); 112 | ``` 113 | 114 | ### Progress 115 | 116 | ![](demo/assets/sbt-progress.gif) 117 | 118 | Method allowed to use Toolbar's underlayer as a progressbar. 119 | 120 | Before some process starts, call 121 | 122 | ```js 123 | startProgress({color, estimate}) 124 | 125 | ``` 126 | 127 | and after finish, call 128 | 129 | ```js 130 | stopProgress() 131 | ``` 132 | 133 | The first method begins to increase with of the underlayer up to 90% and stop there for waiting `stopProgress`. 134 | For better experience your can pass average time of the process via `estimate` option. 135 | 136 | param | type | default | description 137 | -- | -- | -- | -- 138 | `color` | _string_ | #05c7ff | loader color 139 | `estimate` | _number_ | 3500 | average time of the process 140 | 141 | Usage example 142 | 143 | ```js 144 | /** 145 | * Call before the process (for example, AJAX request) 146 | */ 147 | toolbarPane.startProgress({ 148 | color: "#05c7ff", 149 | estimate: 3500 150 | }); 151 | 152 | /** 153 | * Call after the process will be finished 154 | * We use the timeout for the demonstration 155 | */ 156 | setTimeout(function(){ 157 | toolbarPane.stopProgress(); 158 | }, 4850); 159 | ``` 160 | 161 | 162 | ### Reinit 163 | 164 | Can be used to reinitialize the Module with new options 165 | 166 | ```js 167 | reinit({color}) 168 | ``` 169 | 170 | param | type | default | description 171 | -- | -- | -- | -- 172 | `color` | _string_ | - | Toolbar color. **Required** 173 | 174 | 175 | ### Stop blinking 176 | 177 | Used to stop blinking effect 178 | 179 | ```js 180 | stopBlinking() 181 | ``` 182 | 183 | 184 | ### Stop animation 185 | 186 | Used to stop the animation 187 | 188 | ```js 189 | stopAnimation() 190 | ``` 191 | 192 | 193 | ### Stop all effects 194 | 195 | Combines `stopBlinking`, `stopAnimation` and `stopProgress` 196 | 197 | ```js 198 | stopAllEffects() 199 | ``` 200 | 201 | 202 | ### Destroy 203 | 204 | Totally removes all Module's stuff. 205 | 206 | ```js 207 | destroy() 208 | ``` 209 | 210 | 211 | -------------------------------------------------------------------------------- /dist/sct.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.SBToolbar=e():t.SBToolbar=e()}(window,function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)i.d(n,o,function(e){return t[e]}.bind(null,o));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0)}([function(t,e,i){"use strict"; 2 | /** 3 | * Safari Beauty Toolbar 4 | * {@link https://github.com/neSpecc/safari-beauty-toolbar} 5 | * 6 | * Make the Safari Toolbar more consistent with your brand colors. 7 | * Works only on the MacOS, Safari browser that has native toolbar's opacity 8 | * 9 | * 10 | * @author Petr Savchenko 11 | * @see CodeX - team of enthusiasts developers unifying students and graduates of the ITMO University {@link https://ifmo.su} 12 | * @license MIT 13 | * @preserve 14 | */var n;t.exports=((n=function(){function t(t){this.initialized=!1,this.currentColorIndex=0,t&&t.color?(this.color=t.color,this.init()):this.log("«color» option is missed")}return t.prototype.destroy=function(){this.initialized&&(this.stopAnimation(),this.stopBlinking(),this.underlayer.remove(),this.underlayer=null,this.color=null,this.initialized=!1)},t.prototype.reinit=function(t){this.destroy(),t&&t.color&&(this.color=t.color),this.init()},t.prototype.blink=function(t){var e=this;void 0===t&&(t={interval:400,transitionSpeed:500}),this.initialized?(this.stopAllEffects(),this.underlayer.style["will-change"]="opacity",isNaN(t.transitionSpeed)?this.log("transitionSpeed must be a number"):this.underlayer.style.transition="opacity "+t.transitionSpeed+"ms ease",this.blinkingInterval=setInterval(function(){"1"===e.underlayer.style.opacity?e.underlayer.style.opacity="0":e.underlayer.style.opacity="1"},t.interval)):this.log("Module was not initialized")},t.prototype.animate=function(t){var e=this;if(this.initialized)if(t&&t.colors){this.stopAllEffects(),this.underlayer.style["will-change"]="background-color";var i=800;t&&t.speed&&!isNaN(t.speed)&&(i=t.speed),this.underlayer.style.transition="background-color "+Math.floor(i/1.1)+"ms ease",this.animationInterval=setInterval(function(){e.underlayer.style.backgroundColor=t.colors[e.currentColorIndex],e.currentColorIndex++,e.currentColorIndex>t.colors.length&&(e.currentColorIndex=0)},i)}else this.log("Missed required parameter «colors» (array of strings) for the animation");else this.log("Module was not initialized")},t.prototype.startProgress=function(t){var e=this,i=void 0===t?{color:"#05c7ff",estimate:3500}:t,n=i.color,o=i.estimate;this.initialized?(this.stopAnimation(),this.stopBlinking(),this.underlayer.style.transition="none",this.underlayer.style.width="0",this.underlayer.style.transition="width "+(o||3500)+"ms cubic-bezier(.12,.63,.81,.44)",this.underlayer.style.backgroundColor=n||"#05c7ff",setTimeout(function(){e.underlayer.style.width="90%"},100)):this.log("Module was not initialized")},t.prototype.stopProgress=function(){var t=this;this.underlayer.style.width="100%",setTimeout(function(){t.underlayer.style.width="auto"},200)},t.prototype.stopBlinking=function(){this.initialized&&this.blinkingInterval&&(clearTimeout(this.blinkingInterval),this.blinkingInterval=null,this.underlayer.style.opacity="1")},t.prototype.stopAnimation=function(){this.initialized&&this.animationInterval&&(clearTimeout(this.animationInterval),this.animationInterval=null,this.currentColorIndex=0,this.underlayer.style.backgroundColor=this.color)},t.prototype.stopAllEffects=function(){this.stopAnimation(),this.stopBlinking(),this.stopProgress()},t.prototype.init=function(){t.supported?(this.underlayer=this.make(),this.initialized=!0):this.log("Module is not supported by current platform")},Object.defineProperty(t,"supported",{get:function(){return t.isSafari&&(t.isMac||t.isIOS)},enumerable:!0,configurable:!0}),Object.defineProperty(t,"isMac",{get:function(){return navigator.platform.toUpperCase().indexOf("MAC")>=0},enumerable:!0,configurable:!0}),Object.defineProperty(t,"isIOS",{get:function(){return!!navigator.platform.match(/(iPhone|iPod|iPad)/i)},enumerable:!0,configurable:!0}),Object.defineProperty(t,"isSafari",{get:function(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)},enumerable:!0,configurable:!0}),t.prototype.log=function(t){window.console&&window.console.log("%cSBToolbar%c"+t,"color: #047ec6;\n font-size: 11.8px;\n letter-spacing: 3px;\n border: 1px solid #047ec6;\n border-radius: 3px;\n display: inline-block;\n padding: 1px 3px;\n margin-right: 5px","")},t.prototype.make=function(){var t=document.createElement("div");return t.style.position="fixed",t.style.top="0",t.style.left="0",t.style.right="0",t.style.height="100px",t.style.transform="translateY(-99.99%)",t.style.zIndex="9999",t.style.backgroundColor=this.color,t.setAttribute("name","safari-colorful-toolbar"),document.body.appendChild(t),t},t}()).version="1.0.0",n)}])}); -------------------------------------------------------------------------------- /demo/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Safari Beauty Toolbar 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |

Safari Beauty Toolbar

22 |

Make the Safari Toolbar more consistent with your brand colors

23 |
24 | Tiny zero-dependencies JavaScript module 25 |
26 | 27 | View on the GitHub 28 | 29 |
30 | 31 | Available via Yarn 32 | 33 | 34 | Available via NPM 35 | 36 |
37 |
38 |
39 | 103 |
104 |

How it works

105 |

106 | Module works only on the Safari browser on MacOS and iOS because they have a little transparency on the Toolbar. 107 | So we can add the colorful layer and place it under the Toolbar. That's it. This tool just simplifies the trick. 108 |

109 |
110 |
111 | 114 |
115 |
116 | 119 |
120 |
121 |
122 | 126 |
127 |
128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /demo/demo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Example module wrapper 3 | * @author Petr Savchenko 4 | * @see {@link https://ifmo.su/beauty-toolbar} 5 | * 6 | * ƪ(˘⌣˘)ʃ 7 | */ 8 | 'use strict'; 9 | 10 | var demo = function (demo) { 11 | 12 | /** 13 | * Toolbar class instance 14 | * @type {SBToolbar|null} 15 | */ 16 | var toolbarPane = null; 17 | 18 | /** 19 | * Example module initialization 20 | */ 21 | demo.init = function () { 22 | 23 | var demoContainer = document.getElementById('js-demo'); 24 | 25 | if (!demo.supported){ 26 | return; 27 | } 28 | 29 | demoContainer.hidden = false; 30 | 31 | 32 | /** 33 | * Set the Toolbar to Blue 34 | */ 35 | toolbarPane = new SBToolbar({ 36 | color: "#0591ff" 37 | }); 38 | 39 | }; 40 | 41 | /** 42 | * Example of animation calling 43 | */ 44 | demo.animate = function (button) { 45 | 46 | resetButtons(button); 47 | 48 | if (!button.classList.toggle('toggled')){ 49 | 50 | toolbarPane.stopAnimation(); 51 | 52 | button.textContent = button.dataset.startText; 53 | 54 | } else { 55 | 56 | toolbarPane.animate({ 57 | colors: ["rgb(255, 10, 138)", "blue", "#61ffa7", "#ffeb9c"], 58 | speed: 600 59 | }); 60 | 61 | button.dataset.startText = button.textContent; 62 | button.textContent = 'Stop this'; 63 | 64 | } 65 | 66 | }; 67 | 68 | 69 | /** 70 | * Example of blink calling 71 | */ 72 | demo.blink = function (button) { 73 | 74 | resetButtons(button); 75 | 76 | if (!button.classList.toggle('toggled')){ 77 | 78 | toolbarPane.stopBlinking(); 79 | 80 | button.textContent = button.dataset.startText; 81 | 82 | } else { 83 | 84 | toolbarPane.blink({ 85 | interval: 300, 86 | transitionSpeed: 500 87 | }); 88 | 89 | button.dataset.startText = button.textContent; 90 | button.textContent = 'Stop Blinking'; 91 | 92 | } 93 | }; 94 | 95 | /** 96 | * Example of progress calling 97 | */ 98 | demo.progress = function (button) { 99 | 100 | resetButtons(button); 101 | 102 | if (button.classList.contains('toggled')){ 103 | return; 104 | } 105 | 106 | /** 107 | * Call before the process (for example, AJAX request) 108 | */ 109 | toolbarPane.startProgress({ 110 | color: "#05c7ff", 111 | estimate: 3500 112 | }); 113 | 114 | button.classList.add('toggled'); 115 | 116 | /** 117 | * Call after the process will be finished 118 | * We use the timeout for the demonstration 119 | */ 120 | setTimeout(function(){ 121 | toolbarPane.stopProgress(); 122 | 123 | button.classList.remove('toggled'); 124 | }, 4850); 125 | 126 | }; 127 | 128 | /** 129 | * Changes Toolbar color 130 | * @param {string} color - new Toolbar's color 131 | */ 132 | demo.reset = function (color) { 133 | 134 | var colorValueHolder = document.getElementById('js-color-value'); 135 | 136 | colorValueHolder.textContent = '"' + color + '"'; 137 | 138 | toolbarPane.reinit({ 139 | color: color 140 | }); 141 | }; 142 | 143 | /** 144 | * Reset activated button 145 | * @param {HTMLElement} elToSkip - current clicked button 146 | */ 147 | function resetButtons(elToSkip) { 148 | var buttons = document.querySelectorAll('.toggled'); 149 | 150 | if (!buttons.length){ 151 | return; 152 | } 153 | 154 | Array.prototype.slice.call(buttons).forEach(function (button) { 155 | if (button === elToSkip){ 156 | return; 157 | } 158 | button.classList.remove('toggled'); 159 | button.textContent = button.dataset.startText || button.textContent; 160 | }); 161 | } 162 | 163 | /** 164 | * Detect when module can be used 165 | * @return {boolean} 166 | */ 167 | demo.supported = function(){ 168 | return isSafari() && (isMac() || isIOS()); 169 | }(); 170 | 171 | /** 172 | * Check if current platform is the Mac 173 | * @return {boolean} 174 | */ 175 | function isMac() { 176 | return navigator.platform.toUpperCase().indexOf("MAC") >= 0; 177 | } 178 | 179 | /** 180 | * Check if current platform is the IOS 181 | * @return {boolean} 182 | */ 183 | function isIOS() { 184 | return !!navigator.platform.match(/(iPhone|iPod|iPad)/i); 185 | } 186 | 187 | /** 188 | * Check if current browser is a Safari 189 | * @return {boolean} 190 | */ 191 | function isSafari() { 192 | return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); 193 | } 194 | 195 | return demo; 196 | 197 | }({}); 198 | 199 | 200 | /** 201 | * Simple rotator for the screenshots 202 | * @author Petr Savchenko 203 | * @see {@link https://ifmo.su/beauty-toolbar} 204 | */ 205 | /** 206 | * @constructor 207 | * @param {string} sel - items' selector 208 | */ 209 | var Rotator = function (sel) { 210 | 211 | /** 212 | * Find all items 213 | * @type {NodeListOf} 214 | */ 215 | this.items = document.querySelectorAll('.' + sel); 216 | 217 | /** 218 | * BEM modifiers map 219 | * @type {{main: string, last: string, first: string}} 220 | */ 221 | this.css = { 222 | main: sel + '--main', 223 | last: sel + '--last', 224 | first: sel + '--first' 225 | }; 226 | 227 | /** 228 | * Find current main item 229 | * @type {Element | null} 230 | */ 231 | this.current = document.querySelector('.' + this.css.main); 232 | this.currentIndex = Array.prototype.indexOf.call(this.current.parentNode.children, this.current); 233 | 234 | for (var i = 0; i < this.items.length; i++){ 235 | this.items[i].addEventListener('click', itemClicked.bind(this)); 236 | } 237 | 238 | /** 239 | * Item click listener: pass clicked item to the 'set' method 240 | * @param event 241 | */ 242 | function itemClicked (event) { 243 | var clicked = event.target; 244 | var clickedIndex = Array.prototype.indexOf.call(clicked.parentNode.children, clicked); 245 | 246 | if (clickedIndex === this.currentIndex){ 247 | return; 248 | } 249 | 250 | this.set(clickedIndex); 251 | } 252 | }; 253 | 254 | /** 255 | * Replace passed item with main item 256 | * @param {number} index - index of clicked item 257 | */ 258 | Rotator.prototype.set = function (index) { 259 | 260 | var itemToSelect = this.items[index]; 261 | 262 | var isFirst = itemToSelect.classList.contains(this.css.first); 263 | var isLast = itemToSelect.classList.contains(this.css.last); 264 | 265 | if (isFirst) { 266 | this.current.classList.add(this.css.first); 267 | itemToSelect.classList.remove(this.css.first); 268 | } else if (isLast){ 269 | this.current.classList.add(this.css.last); 270 | itemToSelect.classList.remove(this.css.last); 271 | } 272 | 273 | this.current.classList.remove(this.css.main); 274 | itemToSelect.classList.add(this.css.main); 275 | 276 | this.currentIndex = index; 277 | this.current = itemToSelect; 278 | }; 279 | 280 | -------------------------------------------------------------------------------- /src/sct.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Safari Beauty Toolbar 3 | * {@link https://github.com/neSpecc/safari-beauty-toolbar} 4 | * 5 | * Make the Safari Toolbar more consistent with your brand colors. 6 | * Works only on the MacOS, Safari browser that has native toolbar's opacity 7 | * 8 | * 9 | * @author Petr Savchenko 10 | * @see CodeX - team of enthusiasts developers unifying students and graduates of the ITMO University {@link https://ifmo.su} 11 | * @license MIT 12 | * @preserve 13 | */ 14 | 15 | /** 16 | * Configuration object 17 | */ 18 | interface ISBTConfig { 19 | /** 20 | * @type {string} toolbar liner's color; 21 | */ 22 | color: string; 23 | } 24 | 25 | /** 26 | * Blinking configuration object 27 | */ 28 | interface IBlinkingParams { 29 | /** 30 | * Interval for opacity changing 31 | */ 32 | interval?: number; 33 | 34 | /** 35 | * Speed of opacity changing 36 | */ 37 | transitionSpeed?: number; 38 | } 39 | 40 | /** 41 | * Blinking configuration object 42 | */ 43 | interface IAnimationParams { 44 | /** 45 | * List of colors to change 46 | */ 47 | colors?: string[]; 48 | 49 | /** 50 | * Speed of opacity changing 51 | */ 52 | speed?: number; 53 | } 54 | 55 | export = class SBToolbar { 56 | /** 57 | * Current revision number 58 | */ 59 | public static readonly version: string = "1.0.0"; 60 | 61 | /** 62 | * Initialization state 63 | * @type {boolean} 64 | */ 65 | private initialized: boolean = false; 66 | 67 | /** 68 | * @type {string} underlayer color 69 | */ 70 | private color: string; 71 | 72 | /** 73 | * Layer below the Toolbar 74 | * @type {HTMLElement} 75 | */ 76 | private underlayer: HTMLElement; 77 | 78 | /** 79 | * intervalID for the blinking process 80 | * @type {number} 81 | */ 82 | private blinkingInterval: number; 83 | 84 | /** 85 | * intervalID for the animation process 86 | * @type {number} 87 | */ 88 | private animationInterval: number; 89 | 90 | /** 91 | * Index of color-list for the animation process 92 | * @type {number} 93 | */ 94 | private currentColorIndex: number = 0; 95 | 96 | /** 97 | * @constructor 98 | * @param options 99 | */ 100 | constructor(options: ISBTConfig) { 101 | 102 | if (!options || !options.color) { 103 | this.log("«color» option is missed"); 104 | return; 105 | } 106 | 107 | this.color = options.color; 108 | 109 | /** 110 | * Check for support and initialize the Toolbar liner 111 | */ 112 | this.init(); 113 | } 114 | 115 | /** 116 | * Destroys the underlayer 117 | */ 118 | public destroy(): void { 119 | if (!this.initialized) { 120 | return; 121 | } 122 | 123 | this.stopAnimation(); 124 | this.stopBlinking(); 125 | 126 | this.underlayer.remove(); 127 | this.underlayer = null; 128 | this.color = null; 129 | 130 | this.initialized = false; 131 | } 132 | 133 | /** 134 | * Reinitialize the Toolbar liner 135 | * @param {ISBTConfig} [options] - you can reinitialize module with the different settings 136 | */ 137 | public reinit(options: ISBTConfig): void { 138 | this.destroy(); 139 | 140 | if (options && options.color) { 141 | this.color = options.color; 142 | } 143 | 144 | /** 145 | * Check for support and initialize the Toolbar liner 146 | */ 147 | this.init(); 148 | } 149 | 150 | /** 151 | * Start blinking process; 152 | * @param {IBlinkingParams} params - supported blinking options 153 | * @param {number} params.interval - blinking interval, default is 400 154 | * @param {number} params.transitionSpeed - speed of opacity changing, default is 500 155 | */ 156 | public blink(params: IBlinkingParams = {interval: 400, transitionSpeed: 500}): void { 157 | if (!this.initialized) { 158 | this.log("Module was not initialized"); 159 | return; 160 | } 161 | 162 | /** 163 | * Stop all previously fired animations 164 | */ 165 | this.stopAllEffects(); 166 | 167 | this.underlayer.style["will-change"] = "opacity"; 168 | 169 | if (!isNaN(params.transitionSpeed)) { 170 | this.underlayer.style.transition = `opacity ${params.transitionSpeed}ms ease`; 171 | } else { 172 | this.log("transitionSpeed must be a number"); 173 | } 174 | 175 | this.blinkingInterval = setInterval(() => { 176 | if (this.underlayer.style.opacity === "1") { 177 | this.underlayer.style.opacity = "0"; 178 | } else { 179 | this.underlayer.style.opacity = "1"; 180 | } 181 | }, params.interval); 182 | } 183 | 184 | /** 185 | * Start changing colors animatedly 186 | */ 187 | public animate(params: IAnimationParams): void { 188 | if (!this.initialized) { 189 | this.log("Module was not initialized"); 190 | return; 191 | } 192 | 193 | if (!params || !params.colors) { 194 | this.log("Missed required parameter «colors» (array of strings) for the animation"); 195 | return; 196 | } 197 | 198 | /** 199 | * Stop all previously fired animations 200 | */ 201 | this.stopAllEffects(); 202 | 203 | this.underlayer.style["will-change"] = "background-color"; 204 | 205 | let speed = 800; 206 | 207 | if (params && params.speed && !isNaN(params.speed)) { 208 | speed = params.speed; 209 | } 210 | 211 | this.underlayer.style.transition = `background-color ${Math.floor(speed / 1.1)}ms ease`; 212 | 213 | this.animationInterval = setInterval(() => { 214 | 215 | this.underlayer.style.backgroundColor = params.colors[this.currentColorIndex]; 216 | this.currentColorIndex++; 217 | 218 | if (this.currentColorIndex > params.colors.length) { 219 | this.currentColorIndex = 0; 220 | } 221 | 222 | }, speed); 223 | } 224 | 225 | /** 226 | * Show progress bar animation at the toolbar 227 | * @param {string} [color] - bar color. Blue by default 228 | * @param {string} [estimate] - estimate loading time in milliseconds. Uses as the animation speed. 229 | */ 230 | public startProgress({color, estimate} = {color: "#05c7ff", estimate: 3500}): void { 231 | 232 | if (!this.initialized) { 233 | this.log("Module was not initialized"); 234 | return; 235 | } 236 | 237 | this.stopAnimation(); 238 | this.stopBlinking(); 239 | 240 | this.underlayer.style.transition = `none`; 241 | this.underlayer.style.width = "0"; 242 | this.underlayer.style.transition = `width ${estimate || 3500}ms cubic-bezier(.12,.63,.81,.44)`; 243 | this.underlayer.style.backgroundColor = color || "#05c7ff"; 244 | 245 | setTimeout(() => { 246 | this.underlayer.style.width = "90%"; 247 | }, 100); 248 | } 249 | 250 | /** 251 | * Finish progressbar animation 252 | */ 253 | public stopProgress(): void { 254 | this.underlayer.style.width = "100%"; 255 | 256 | setTimeout(() => { 257 | this.underlayer.style.width = "auto"; 258 | }, 200); 259 | } 260 | 261 | /** 262 | * Stop the blinking process 263 | */ 264 | public stopBlinking(): void { 265 | if (this.initialized && this.blinkingInterval) { 266 | clearTimeout(this.blinkingInterval); 267 | this.blinkingInterval = null; 268 | this.underlayer.style.opacity = "1"; 269 | } 270 | } 271 | 272 | /** 273 | * Stop the animation process 274 | */ 275 | public stopAnimation(): void { 276 | if (this.initialized && this.animationInterval) { 277 | clearTimeout(this.animationInterval); 278 | this.animationInterval = null; 279 | this.currentColorIndex = 0; 280 | this.underlayer.style.backgroundColor = this.color; 281 | } 282 | } 283 | 284 | /** 285 | * Stop all animations 286 | */ 287 | public stopAllEffects(): void { 288 | this.stopAnimation(); 289 | this.stopBlinking(); 290 | this.stopProgress(); 291 | } 292 | 293 | /** 294 | * Initialize the Toolbar 295 | */ 296 | private init(): void { 297 | 298 | if (!SBToolbar.supported) { 299 | this.log("Module is not supported by current platform"); 300 | return; 301 | } 302 | 303 | /** 304 | * Append the Underlayer 305 | * @type {Element} 306 | */ 307 | this.underlayer = this.make(); 308 | 309 | /** 310 | * Toggle initialization state 311 | * @type {boolean} 312 | */ 313 | this.initialized = true; 314 | } 315 | 316 | /** 317 | * Detect when module can be used 318 | * @return {boolean} 319 | */ 320 | private static get supported(): boolean { 321 | return SBToolbar.isSafari && (SBToolbar.isMac || SBToolbar.isIOS); 322 | } 323 | 324 | /** 325 | * Check if current platform is the Mac 326 | * @return {boolean} 327 | */ 328 | private static get isMac(): boolean { 329 | return navigator.platform.toUpperCase().indexOf("MAC") >= 0; 330 | } 331 | 332 | /** 333 | * Check if current platform is the IOS 334 | * @return {boolean} 335 | */ 336 | private static get isIOS(): boolean { 337 | return !!navigator.platform.match(/(iPhone|iPod|iPad)/i); 338 | } 339 | 340 | /** 341 | * Check if current browser is a Safari 342 | * @return {boolean} 343 | */ 344 | private static get isSafari(): boolean { 345 | return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); 346 | } 347 | 348 | /** 349 | * Write log to the Console 350 | * @param {string} output 351 | */ 352 | private log(output: string): void { 353 | const style = `color: #047ec6; 354 | font-size: 11.8px; 355 | letter-spacing: 3px; 356 | border: 1px solid #047ec6; 357 | border-radius: 3px; 358 | display: inline-block; 359 | padding: 1px 3px; 360 | margin-right: 5px`; 361 | 362 | if (window.console) { 363 | window.console.log("%cSBToolbar" + "%c" + output, style, ""); 364 | } 365 | } 366 | 367 | /** 368 | * Make the underlayer and append to the DOM 369 | * @return {HTMLElement} 370 | */ 371 | private make(): HTMLElement { 372 | const liner = document.createElement("div"); 373 | 374 | liner.style.position = "fixed"; 375 | liner.style.top = "0"; 376 | liner.style.left = "0"; 377 | liner.style.right = "0"; 378 | liner.style.height = "100px"; 379 | liner.style.transform = "translateY(-99.99%)"; 380 | liner.style.zIndex = "9999"; 381 | liner.style.backgroundColor = this.color; 382 | 383 | liner.setAttribute("name", "safari-colorful-toolbar"); 384 | 385 | document.body.appendChild(liner); 386 | 387 | return liner; 388 | } 389 | } 390 | -------------------------------------------------------------------------------- /demo/demo.pcss: -------------------------------------------------------------------------------- 1 | 2 | 3 | /********/ 4 | 5 | 6 | :root { 7 | --text-gray: #666A75; 8 | --text-link: #99A1AE; 9 | --bg-main: #23242C; 10 | --bg-button: #3C78D0; 11 | 12 | @custom-media --mobile all and (max-width: 980px); 13 | @custom-media --desktop all and (min-width: 981px); 14 | } 15 | 16 | body { 17 | margin: 0; 18 | background: var(--bg-main); 19 | } 20 | 21 | .sct { 22 | background: var(--bg-main); 23 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI", "Roboto", Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; 24 | padding-bottom: 100px; 25 | line-height: initial; 26 | 27 | &__center-side { 28 | max-width: 1000px; 29 | margin: 0 auto; 30 | 31 | @media (--mobile) { 32 | padding-left: 20px; 33 | padding-right: 20px; 34 | } 35 | } 36 | 37 | &__header { 38 | background: #1D1F26; 39 | color: var(--text-gray); 40 | 41 | text-align: center; 42 | padding: 90px 0 40px; 43 | 44 | @media (--mobile) { 45 | padding: 50px 0 30px; 46 | } 47 | 48 | h1 { 49 | color: #fff; 50 | font-size: 57px; 51 | font-weight: 800; 52 | margin-bottom: 10px; 53 | letter-spacing: -0.88px; 54 | 55 | @media (--mobile) { 56 | font-size: 8vw; 57 | } 58 | } 59 | 60 | h2 { 61 | margin-top: 5px; 62 | font-weight: normal; 63 | font-size: 27px; 64 | letter-spacing: 0.22px; 65 | line-height: 1.45em; 66 | 67 | @media (--mobile) { 68 | font-size: 5vw; 69 | } 70 | } 71 | 72 | &-caption { 73 | font-size: 15.4px; 74 | letter-spacing: 0.13px; 75 | margin-bottom: 30px; 76 | 77 | @media (--mobile) { 78 | font-size: 3vw; 79 | } 80 | } 81 | 82 | } 83 | 84 | h3 { 85 | margin: 50px 0 20px; 86 | font-weight: 500; 87 | font-size: 18px; 88 | color: #fff; 89 | letter-spacing: 0.68px; 90 | } 91 | 92 | &__rotator { 93 | position: relative; 94 | width: 730px; 95 | height: 304px; 96 | margin: 0 auto; 97 | 98 | @media (--mobile) { 99 | width: auto; 100 | margin-left: -15px; 101 | height: 45vw; 102 | } 103 | 104 | &-item { 105 | position: absolute; 106 | width: 450px; 107 | height: 300px; 108 | background-color: rgb(52, 54, 66); 109 | background-size: cover; 110 | border-radius: 3px; 111 | transition: all 400ms ease; 112 | user-select: none; 113 | cursor: pointer; 114 | 115 | @media (--mobile) { 116 | width: 60vw; 117 | height: 40vw; 118 | } 119 | 120 | &--main { 121 | transform: translateX(31%); 122 | box-shadow: 0 31px 50px 0 rgba(0,0,0,0.49); 123 | opacity: 1; 124 | z-index: 3; 125 | } 126 | 127 | &--last, 128 | &--first { 129 | opacity: 0.3; 130 | } 131 | 132 | &--first { 133 | transform: translateX(0) scale(0.8); 134 | z-index: 2; 135 | } 136 | 137 | &--last { 138 | transform: translateX(63%) scale(0.8); 139 | z-index: 1; 140 | } 141 | } 142 | } 143 | 144 | &__button { 145 | display: inline-block; 146 | padding: 8px 16px; 147 | background: var(--bg-button); 148 | border-radius: 3px; 149 | font-weight: 400; 150 | font-size: 15.3px; 151 | color: rgba(255,255,255,0.86); 152 | letter-spacing: 0.23px; 153 | text-align: center; 154 | cursor: pointer; 155 | text-decoration: none; 156 | user-select: none; 157 | 158 | &:hover { 159 | background: color(var(--bg-button) blackness(+10%)); 160 | } 161 | 162 | &--github { 163 | font-size: 17px; 164 | color: #fff; 165 | padding: 17px 25px; 166 | 167 | @media (--mobile) { 168 | padding: 12px 20px; 169 | font-size: 15px; 170 | } 171 | 172 | &::before { 173 | content: ''; 174 | display: inline-block; 175 | vertical-align: middle; 176 | background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M22.39 6.269A11.948 11.948 0 0 0 18.023 1.9C16.185.828 14.177.292 12 .292c-2.177 0-4.185.537-6.023 1.61a11.946 11.946 0 0 0-4.368 4.367C.536 8.107 0 10.115 0 12.292c0 2.614.763 4.966 2.289 7.054 1.526 2.089 3.497 3.534 5.914 4.336.281.052.49.015.625-.11a.611.611 0 0 0 .203-.468l-.008-.844c-.005-.53-.008-.994-.008-1.39l-.36.062c-.228.042-.517.06-.866.055a6.607 6.607 0 0 1-1.086-.11 2.427 2.427 0 0 1-1.047-.468 1.983 1.983 0 0 1-.688-.96l-.156-.36a3.904 3.904 0 0 0-.492-.797c-.224-.292-.45-.49-.68-.594l-.109-.078a1.147 1.147 0 0 1-.203-.188.857.857 0 0 1-.14-.218c-.032-.073-.006-.133.078-.18.083-.047.234-.07.453-.07l.312.047c.208.041.466.166.773.374.308.209.56.48.758.813.24.427.529.752.867.976.339.224.68.336 1.024.336.343 0 .64-.026.89-.078.25-.052.485-.13.703-.234.094-.698.35-1.235.766-1.61a10.699 10.699 0 0 1-1.602-.281 6.377 6.377 0 0 1-1.468-.61 4.206 4.206 0 0 1-1.258-1.046c-.333-.417-.607-.964-.82-1.641-.214-.677-.32-1.458-.32-2.344 0-1.26.411-2.333 1.234-3.219-.386-.947-.35-2.01.11-3.187.301-.094.75-.023 1.343.211.594.234 1.029.435 1.305.602.276.166.497.307.664.422.969-.271 1.969-.407 3-.407 1.03 0 2.031.136 3 .407l.594-.375c.406-.25.885-.48 1.437-.688.552-.208.974-.265 1.266-.172.469 1.177.51 2.24.125 3.188.823.885 1.234 1.958 1.234 3.218 0 .886-.107 1.67-.32 2.352-.213.682-.49 1.229-.828 1.64-.339.412-.76.758-1.266 1.04a6.389 6.389 0 0 1-1.468.609c-.474.125-1.008.22-1.602.282.542.468.812 1.208.812 2.218v3.297c0 .187.065.343.196.468.13.125.336.162.617.11 2.417-.802 4.388-2.248 5.914-4.336C23.237 17.257 24 14.906 24 12.29c0-2.176-.537-4.184-1.61-6.022z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E"); 177 | width: 24px; 178 | height: 24px; 179 | margin-top: -0.2em; 180 | margin-right: 0.35em; 181 | 182 | @media (--mobile) { 183 | width: 20px; 184 | height: 20px; 185 | background-size: 20px auto; 186 | } 187 | } 188 | } 189 | 190 | &.toggled { 191 | background-color: #4D5263; 192 | color: #AEB7CD; 193 | } 194 | } 195 | 196 | &__link { 197 | display: inline-block; 198 | margin-top: 20px; 199 | padding: 10px; 200 | text-decoration: none; 201 | font-size: 13.5px; 202 | letter-spacing: 0.37px; 203 | 204 | @media (--mobile) { 205 | padding: 5px; 206 | margin-top: 15px; 207 | font-size: 0; 208 | opacity: 1; 209 | } 210 | 211 | &::before { 212 | content: ''; 213 | display: inline-block; 214 | vertical-align: middle; 215 | margin-right: 3px; 216 | } 217 | 218 | &:hover { 219 | opacity: 0.9; 220 | } 221 | 222 | &--yarn { 223 | color: #397FB1; 224 | 225 | &::before { 226 | background-image: url("data:image/svg+xml,%3Csvg width='52' height='23' viewBox='0 0 52 23' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill-rule='nonzero' fill='none'%3E%3Cpath d='M31.805 11.447a7.036 7.036 0 0 1-1.558 2.824V8.037c0-.427-.372-.782-.956-.782-.248 0-.46.125-.46.302 0 .124.07.231.07.568v2.86c-.212 1.243-.743 2.398-1.451 2.398-.514 0-.815-.515-.815-1.475 0-1.491.195-2.273.514-3.587.07-.267.584-.977-.283-.977-.939 0-.815.355-.939.657 0 0-.593 2.114-.593 3.996 0 1.545.646 2.558 1.833 2.558.76 0 1.31-.515 1.735-1.226v2.256c-1.169 1.03-2.196 1.936-2.196 3.73 0 1.136.708 2.042 1.7 2.042.903 0 1.841-.657 1.841-2.522v-3.072c.956-.835 1.983-1.883 2.585-3.943.018-.071.018-.16.018-.178 0-.337-.337-.728-.62-.728-.177 0-.319.16-.425.533zm-3.4 8.791c-.282 0-.46-.426-.46-.977 0-1.065.39-1.74.957-2.326v1.9c0 .338.07 1.403-.496 1.403zm8.481-6.873c-.425 0-.602-.426-.602-.817v-2.93c0-.427-.372-.782-.956-.782-.248 0-.46.124-.46.302 0 .124.07.23.07.568v2.735c-.194.498-.513.924-.99.924-.62 0-1.01-.533-1.01-1.457 0-2.557 1.576-3.711 2.921-3.711.177 0 .354.035.514.035.177 0 .23-.107.23-.408 0-.462-.337-.746-.815-.746-2.16 0-4.213 1.811-4.213 4.777 0 1.51.726 2.682 2.107 2.682.672 0 1.168-.32 1.522-.728.266.426.744.728 1.363.728 1.523 0 2.231-1.598 2.532-2.77.018-.072.018-.107.018-.125 0-.337-.337-.728-.62-.728-.177 0-.354.16-.425.533-.16.781-.478 1.918-1.186 1.918zm5.116 1.172c1.523 0 2.213-1.598 2.532-2.77 0-.036.018-.072.018-.125 0-.337-.337-.728-.62-.728-.177 0-.354.16-.425.533-.159.781-.46 1.918-1.274 1.918-.478 0-.709-.462-.709-.96 0-1.775.797-3.871.797-4.084.07-.409-.637-.995-.85-.995h-.92c-.177 0-.354 0-.939-.07-.194-.729-.69-.942-1.115-.942-.46 0-.885.32-.885.817 0 .515.319.888.761 1.137-.018.905-.088 2.38-.283 3.09-.16.604.761 1.243.991.497.319-1.03.425-2.575.443-3.268h1.54c-.566 1.528-.885 2.789-.885 3.925 0 1.563.991 2.025 1.823 2.025zm1.576-.781c0 .657.496.781.85.781.513 0 .496-.426.496-.764V11.18c.124-1.403 1.221-2.93 1.735-2.93.336 0 .371.462.371 1.012v3.606c0 .905.55 1.67 1.487 1.67 1.523 0 2.275-1.6 2.576-2.772.018-.07.018-.106.018-.124 0-.337-.336-.728-.62-.728-.177 0-.354.16-.424.533-.16.781-.523 1.918-1.23 1.918-.461 0-.461-.657-.461-.817V8.87c0-.817-.283-1.793-1.47-1.793-.867 0-1.504.763-1.982 1.758v-.8c0-.426-.372-.78-.956-.78-.248 0-.46.124-.46.301 0 .124.07.231.07.568v5.63zM11.463 0c6.33 0 11.464 5.15 11.464 11.5S17.792 23 11.463 23C5.134 23 0 17.85 0 11.5S5.134 0 11.463 0z' fill='%23397FB1'/%3E%3Cpath d='M19.157 14.802c-.08-.626-.608-1.058-1.287-1.05-1.014.014-1.865.539-2.43.887-.22.136-.41.238-.572.313a4.677 4.677 0 0 0-.26-1.917c-.322-.882-.754-1.424-1.063-1.737.357-.52.847-1.278 1.076-2.45.198-1 .136-2.556-.318-3.428a.702.702 0 0 0-.44-.357c-.08-.022-.23-.066-.525.017-.445-.92-.6-1.018-.719-1.097a.9.9 0 0 0-.81-.093c-.367.133-.68.485-.975 1.11-.044.093-.084.182-.12.27a3.25 3.25 0 0 0-2.186 1.049c-.092.101-.273.176-.463.246h.005c-.388.137-.565.454-.78 1.027-.3.802.008 1.591.312 2.102-.414.37-.965.96-1.256 1.653a5.255 5.255 0 0 0-.388 2.146c-.309.326-.785.939-.838 1.626-.07.96.278 1.613.432 1.85.045.071.093.129.146.186a1.022 1.022 0 0 0 .551 1.097c.582.309 1.393.441 2.02.128.224.238.634.467 1.379.467h.044c.19 0 2.597-.128 3.298-.3.313-.074.529-.207.67-.326.45-.14 1.693-.564 2.865-1.322.83-.537 1.116-.652 1.733-.802.6-.145.974-.692.9-1.295zm-1.05.648c-.704.167-1.062.321-1.934.89-1.363.881-2.853 1.29-2.853 1.29s-.123.186-.48.27c-.617.15-2.94.277-3.152.282-.569.004-.917-.146-1.014-.38-.296-.704.423-1.013.423-1.013s-.159-.097-.251-.185c-.084-.084-.172-.251-.199-.19-.11.27-.167.926-.463 1.221-.405.41-1.172.274-1.626.036-.499-.265.035-.886.035-.886s-.269.158-.485-.168c-.194-.3-.375-.81-.326-1.44.053-.719.855-1.415.855-1.415s-.141-1.062.322-2.15c.419-.992 1.547-1.79 1.547-1.79s-.948-1.049-.595-1.992c.23-.617.322-.612.397-.639.264-.101.52-.211.71-.419.947-1.022 2.155-.828 2.155-.828s.573-1.74 1.102-1.401c.164.105.75 1.41.75 1.41s.626-.366.696-.23c.38.737.424 2.142.256 2.997-.282 1.41-.987 2.168-1.27 2.644-.066.11.759.459 1.279 1.9.48 1.317.053 2.424.128 2.547l.017.03s.552.045 1.658-.638c.59-.366 1.292-.776 2.09-.785.771-.013.81.89.229 1.032z' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E"); 227 | width: 52px; 228 | height: 23px; 229 | } 230 | } 231 | 232 | &--npm { 233 | color: #D84848; 234 | 235 | &::before { 236 | background-image: url("data:image/svg+xml,%3Csvg width='42' height='16' viewBox='0 0 42 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill-rule='nonzero' fill='none'%3E%3Cpath fill='%23CB3837' d='M0 0v13.714h11.429V16h9.142v-2.286h20.572V0'/%3E%3Cpath fill='%23FFF' d='M2.286 2.286v9.143h4.571V4.57h2.286v6.858h2.286V2.286h2.285v11.428h4.572V4.571h2.285v4.572h-2.285v2.286h4.571V2.286h2.286v9.143h4.571V4.57H32v6.858h2.286V4.57h2.285v6.858h2.286V2.286'/%3E%3C/g%3E%3C/svg%3E"); 237 | width: 42px; 238 | height: 16px; 239 | } 240 | } 241 | } 242 | 243 | &__table { 244 | display: flex; 245 | flex-wrap: wrap; 246 | margin: 30px 0 50px; 247 | flex-direction: column; 248 | 249 | label { 250 | @media (--mobile) { 251 | display: block; 252 | } 253 | } 254 | 255 | &-cell { 256 | padding: 30px 0; 257 | font-size: 18px; 258 | color: var(--text-gray); 259 | letter-spacing: 0.08px; 260 | 261 | &:not(:last-of-type){ 262 | border-bottom: 1px solid #2E3342; 263 | } 264 | 265 | @media (--mobile) { 266 | padding: 20px 0 !important; 267 | } 268 | 269 | code { 270 | display: block; 271 | white-space: pre; 272 | margin-top: 20px; 273 | font-size: 15px; 274 | color: #C2C4D1; 275 | letter-spacing: -0.49px; 276 | line-height: 20px; 277 | font-family: monospace, monospace; 278 | 279 | @media (--mobile) { 280 | font-size: 13px; 281 | max-width: 100%; 282 | overflow-x: auto; 283 | } 284 | } 285 | } 286 | 287 | @supports (display: grid) { 288 | @media (--desktop) { 289 | display: grid; 290 | grid-template-columns: repeat(2, 1fr); 291 | grid-gap: 1px; 292 | grid-auto-rows: minmax(150px, auto); 293 | background: #2E3342; 294 | 295 | @media (--mobile) { 296 | display: block; 297 | background: transparent; 298 | } 299 | 300 | &-cell { 301 | border: 0 !important; 302 | padding: 35px; 303 | background: var(--bg-main); 304 | 305 | /* left side */ 306 | &:nth-of-type(2n+1) { 307 | padding-left: 0; 308 | } 309 | 310 | /* right side */ 311 | &:nth-of-type(2n) { 312 | padding-right: 0; 313 | } 314 | 315 | /* top side */ 316 | &:nth-of-type(1), 317 | &:nth-of-type(2){ 318 | padding-top: 0; 319 | } 320 | 321 | /* bottom side */ 322 | &:nth-last-of-type(1), 323 | &:nth-last-of-type(2){ 324 | padding-bottom: 0; 325 | } 326 | } 327 | } 328 | } 329 | } 330 | 331 | &__table-cell &__button { 332 | float: right; 333 | margin-top: -0.5em; 334 | 335 | @media (--mobile) { 336 | float: none; 337 | margin-top: 15px; 338 | } 339 | } 340 | 341 | &__colors { 342 | float: right; 343 | margin-top: -0.2em; 344 | 345 | @media (--mobile) { 346 | float: none; 347 | display: block; 348 | margin-top: 15px; 349 | } 350 | 351 | &-item { 352 | display: inline-block; 353 | width: 22px; 354 | height: 22px; 355 | border-radius: 3px; 356 | background: #F86464; 357 | margin-left: 8px; 358 | margin-top: -3px; 359 | vertical-align: middle; 360 | cursor: pointer; 361 | 362 | @media (--mobile) { 363 | margin-left: 0; 364 | margin-right: 10px; 365 | width: 30px; 366 | height: 30px; 367 | } 368 | 369 | &--blue { 370 | background: #519AFF; 371 | } 372 | 373 | &--yellow { 374 | background: #F3FF6F; 375 | } 376 | 377 | &--green { 378 | background: #62FF99; 379 | } 380 | 381 | &--pink { 382 | background: #FFC5FA; 383 | } 384 | } 385 | 386 | input { 387 | background: rgba(0,0,0,0.20); 388 | box-shadow: inset 0 4px 4px 0 rgba(0,0,0,0.16); 389 | border-radius: 3px; 390 | font-size: 12px; 391 | color: rgba(255, 255, 255, 0.3); 392 | letter-spacing: 1.1px; 393 | border: 0; 394 | outline: none; 395 | width: 81px; 396 | line-height: 31px; 397 | height: 31px; 398 | text-align: center; 399 | vertical-align: middle; 400 | margin-top: -3px; 401 | } 402 | } 403 | 404 | &__docs { 405 | font-size: 18px; 406 | letter-spacing: 0.15px; 407 | color: var(--text-gray); 408 | 409 | a { 410 | color: var(--text-link); 411 | } 412 | } 413 | 414 | &__how { 415 | p { 416 | max-width: 565px; 417 | font-size: 15.9px; 418 | color: var(--text-gray); 419 | letter-spacing: 0.24px; 420 | line-height: 22px; 421 | } 422 | } 423 | 424 | &__gifs { 425 | display: flex; 426 | justify-content: space-between; 427 | margin-top: 35px; 428 | 429 | @media (--mobile) { 430 | flex-direction: column; 431 | } 432 | 433 | &-item { 434 | width: 47%; 435 | video { 436 | max-width: 100%; 437 | } 438 | 439 | @media (--mobile) { 440 | width: 100%; 441 | height: 65vw; 442 | } 443 | 444 | &:not(:last-of-type){ 445 | @media (--mobile) { 446 | margin-bottom: 20px; 447 | } 448 | } 449 | } 450 | } 451 | 452 | &__footer { 453 | display: flex; 454 | border-top: 1px solid rgba(255,255,255, .1); 455 | margin-top: 50px; 456 | color: var(--text-gray); 457 | font-size: 14.4px; 458 | padding: 20px 0; 459 | line-height: 1.45em; 460 | 461 | @media (--mobile) { 462 | flex-wrap: wrap; 463 | } 464 | 465 | a { 466 | color: var(--text-link); 467 | text-decoration: none; 468 | } 469 | 470 | &-right { 471 | margin-left: auto; 472 | 473 | @media (--mobile) { 474 | margin-top: 15px; 475 | flex-basis: 100%; 476 | } 477 | } 478 | } 479 | } 480 | 481 | /** 482 | * Highlighted code 483 | */ 484 | .hcode { 485 | &--keyword { 486 | color: #7e869b; 487 | } 488 | 489 | &--object { 490 | color: #a2abc1; 491 | } 492 | 493 | &--method { 494 | color: #787c90; 495 | } 496 | 497 | &--property { 498 | color: #85869b; 499 | } 500 | 501 | &--string { 502 | color: #77b188; 503 | } 504 | 505 | &--number { 506 | color: #4ba2d1; 507 | } 508 | } 509 | -------------------------------------------------------------------------------- /demo/demo.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /********/ 4 | 5 | 6 | :root { 7 | } 8 | 9 | body { 10 | margin: 0; 11 | background: #23242C; 12 | } 13 | 14 | .sct { 15 | background: #23242C; 16 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI", "Roboto", Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; 17 | padding-bottom: 100px; 18 | line-height: normal; 19 | line-height: initial; 20 | } 21 | 22 | .sct__center-side { 23 | max-width: 1000px; 24 | margin: 0 auto; 25 | } 26 | 27 | @media all and (max-width: 980px) { 28 | 29 | 30 | .sct__center-side { 31 | padding-left: 20px; 32 | padding-right: 20px; 33 | } 34 | } 35 | 36 | .sct__header { 37 | background: #1D1F26; 38 | color: #666A75; 39 | 40 | text-align: center; 41 | padding: 90px 0 40px; 42 | } 43 | 44 | @media all and (max-width: 980px) { 45 | 46 | 47 | .sct__header { 48 | padding: 50px 0 30px; 49 | } 50 | } 51 | 52 | .sct__header h1 { 53 | color: #fff; 54 | font-size: 57px; 55 | font-weight: 800; 56 | margin-bottom: 10px; 57 | letter-spacing: -0.88px; 58 | } 59 | 60 | @media all and (max-width: 980px) { 61 | 62 | 63 | .sct__header h1 { 64 | font-size: 8vw; 65 | } 66 | } 67 | 68 | .sct__header h2 { 69 | margin-top: 5px; 70 | font-weight: normal; 71 | font-size: 27px; 72 | letter-spacing: 0.22px; 73 | line-height: 1.45em; 74 | } 75 | 76 | @media all and (max-width: 980px) { 77 | 78 | 79 | .sct__header h2 { 80 | font-size: 5vw; 81 | } 82 | } 83 | 84 | .sct__header-caption { 85 | font-size: 15.4px; 86 | letter-spacing: 0.13px; 87 | margin-bottom: 30px; 88 | } 89 | 90 | @media all and (max-width: 980px) { 91 | 92 | 93 | .sct__header-caption { 94 | font-size: 3vw; 95 | } 96 | } 97 | 98 | .sct h3 { 99 | margin: 50px 0 20px; 100 | font-weight: 500; 101 | font-size: 18px; 102 | color: #fff; 103 | letter-spacing: 0.68px; 104 | } 105 | 106 | .sct__rotator { 107 | position: relative; 108 | width: 730px; 109 | height: 304px; 110 | margin: 0 auto; 111 | } 112 | 113 | @media all and (max-width: 980px) { 114 | 115 | 116 | .sct__rotator { 117 | width: auto; 118 | margin-left: -15px; 119 | height: 45vw; 120 | } 121 | } 122 | 123 | .sct__rotator-item { 124 | position: absolute; 125 | width: 450px; 126 | height: 300px; 127 | background-color: rgb(52, 54, 66); 128 | background-size: cover; 129 | border-radius: 3px; 130 | -webkit-transition: all 400ms ease; 131 | transition: all 400ms ease; 132 | -webkit-user-select: none; 133 | -moz-user-select: none; 134 | -ms-user-select: none; 135 | user-select: none; 136 | cursor: pointer; 137 | } 138 | 139 | @media all and (max-width: 980px) { 140 | 141 | 142 | .sct__rotator-item { 143 | width: 60vw; 144 | height: 40vw; 145 | } 146 | } 147 | 148 | .sct__rotator-item--main { 149 | -webkit-transform: translateX(31%); 150 | transform: translateX(31%); 151 | -webkit-box-shadow: 0 31px 50px 0 rgba(0, 0, 0, .49); 152 | box-shadow: 0 31px 50px 0 rgba(0, 0, 0, .49); 153 | opacity: 1; 154 | z-index: 3; 155 | } 156 | 157 | .sct__rotator-item--last, 158 | .sct__rotator-item--first { 159 | opacity: 0.3; 160 | } 161 | 162 | .sct__rotator-item--first { 163 | -webkit-transform: translateX(0) scale(0.8); 164 | transform: translateX(0) scale(0.8); 165 | z-index: 2; 166 | } 167 | 168 | .sct__rotator-item--last { 169 | -webkit-transform: translateX(63%) scale(0.8); 170 | transform: translateX(63%) scale(0.8); 171 | z-index: 1; 172 | } 173 | 174 | .sct__button { 175 | display: inline-block; 176 | padding: 8px 16px; 177 | background: #3C78D0; 178 | border-radius: 3px; 179 | font-weight: 400; 180 | font-size: 15.3px; 181 | color: rgba(255, 255, 255, .86); 182 | letter-spacing: 0.23px; 183 | text-align: center; 184 | cursor: pointer; 185 | text-decoration: none; 186 | -webkit-user-select: none; 187 | -moz-user-select: none; 188 | -ms-user-select: none; 189 | user-select: none; 190 | } 191 | 192 | .sct__button:hover { 193 | background: rgb(61, 110, 184); 194 | } 195 | 196 | .sct__button--github { 197 | font-size: 17px; 198 | color: #fff; 199 | padding: 17px 25px; 200 | } 201 | 202 | @media all and (max-width: 980px) { 203 | 204 | 205 | .sct__button--github { 206 | padding: 12px 20px; 207 | font-size: 15px; 208 | } 209 | } 210 | 211 | .sct__button--github::before { 212 | content: ''; 213 | display: inline-block; 214 | vertical-align: middle; 215 | background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M22.39 6.269A11.948 11.948 0 0 0 18.023 1.9C16.185.828 14.177.292 12 .292c-2.177 0-4.185.537-6.023 1.61a11.946 11.946 0 0 0-4.368 4.367C.536 8.107 0 10.115 0 12.292c0 2.614.763 4.966 2.289 7.054 1.526 2.089 3.497 3.534 5.914 4.336.281.052.49.015.625-.11a.611.611 0 0 0 .203-.468l-.008-.844c-.005-.53-.008-.994-.008-1.39l-.36.062c-.228.042-.517.06-.866.055a6.607 6.607 0 0 1-1.086-.11 2.427 2.427 0 0 1-1.047-.468 1.983 1.983 0 0 1-.688-.96l-.156-.36a3.904 3.904 0 0 0-.492-.797c-.224-.292-.45-.49-.68-.594l-.109-.078a1.147 1.147 0 0 1-.203-.188.857.857 0 0 1-.14-.218c-.032-.073-.006-.133.078-.18.083-.047.234-.07.453-.07l.312.047c.208.041.466.166.773.374.308.209.56.48.758.813.24.427.529.752.867.976.339.224.68.336 1.024.336.343 0 .64-.026.89-.078.25-.052.485-.13.703-.234.094-.698.35-1.235.766-1.61a10.699 10.699 0 0 1-1.602-.281 6.377 6.377 0 0 1-1.468-.61 4.206 4.206 0 0 1-1.258-1.046c-.333-.417-.607-.964-.82-1.641-.214-.677-.32-1.458-.32-2.344 0-1.26.411-2.333 1.234-3.219-.386-.947-.35-2.01.11-3.187.301-.094.75-.023 1.343.211.594.234 1.029.435 1.305.602.276.166.497.307.664.422.969-.271 1.969-.407 3-.407 1.03 0 2.031.136 3 .407l.594-.375c.406-.25.885-.48 1.437-.688.552-.208.974-.265 1.266-.172.469 1.177.51 2.24.125 3.188.823.885 1.234 1.958 1.234 3.218 0 .886-.107 1.67-.32 2.352-.213.682-.49 1.229-.828 1.64-.339.412-.76.758-1.266 1.04a6.389 6.389 0 0 1-1.468.609c-.474.125-1.008.22-1.602.282.542.468.812 1.208.812 2.218v3.297c0 .187.065.343.196.468.13.125.336.162.617.11 2.417-.802 4.388-2.248 5.914-4.336C23.237 17.257 24 14.906 24 12.29c0-2.176-.537-4.184-1.61-6.022z' fill='%23FFF' fill-rule='nonzero'/%3E%3C/svg%3E"); 216 | width: 24px; 217 | height: 24px; 218 | margin-top: -0.2em; 219 | margin-right: 0.35em; 220 | } 221 | 222 | @media all and (max-width: 980px) { 223 | 224 | 225 | .sct__button--github::before { 226 | width: 20px; 227 | height: 20px; 228 | background-size: 20px auto; 229 | } 230 | } 231 | 232 | .sct__button.toggled { 233 | background-color: #4D5263; 234 | color: #AEB7CD; 235 | } 236 | 237 | .sct__link { 238 | display: inline-block; 239 | margin-top: 20px; 240 | padding: 10px; 241 | text-decoration: none; 242 | font-size: 13.5px; 243 | letter-spacing: 0.37px; 244 | } 245 | 246 | @media all and (max-width: 980px) { 247 | 248 | 249 | .sct__link { 250 | padding: 5px; 251 | margin-top: 15px; 252 | font-size: 0; 253 | opacity: 1; 254 | } 255 | } 256 | 257 | .sct__link::before { 258 | content: ''; 259 | display: inline-block; 260 | vertical-align: middle; 261 | margin-right: 3px; 262 | } 263 | 264 | .sct__link:hover { 265 | opacity: 0.9; 266 | } 267 | 268 | .sct__link--yarn { 269 | color: #397FB1; 270 | } 271 | 272 | .sct__link--yarn::before { 273 | background-image: url("data:image/svg+xml,%3Csvg width='52' height='23' viewBox='0 0 52 23' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill-rule='nonzero' fill='none'%3E%3Cpath d='M31.805 11.447a7.036 7.036 0 0 1-1.558 2.824V8.037c0-.427-.372-.782-.956-.782-.248 0-.46.125-.46.302 0 .124.07.231.07.568v2.86c-.212 1.243-.743 2.398-1.451 2.398-.514 0-.815-.515-.815-1.475 0-1.491.195-2.273.514-3.587.07-.267.584-.977-.283-.977-.939 0-.815.355-.939.657 0 0-.593 2.114-.593 3.996 0 1.545.646 2.558 1.833 2.558.76 0 1.31-.515 1.735-1.226v2.256c-1.169 1.03-2.196 1.936-2.196 3.73 0 1.136.708 2.042 1.7 2.042.903 0 1.841-.657 1.841-2.522v-3.072c.956-.835 1.983-1.883 2.585-3.943.018-.071.018-.16.018-.178 0-.337-.337-.728-.62-.728-.177 0-.319.16-.425.533zm-3.4 8.791c-.282 0-.46-.426-.46-.977 0-1.065.39-1.74.957-2.326v1.9c0 .338.07 1.403-.496 1.403zm8.481-6.873c-.425 0-.602-.426-.602-.817v-2.93c0-.427-.372-.782-.956-.782-.248 0-.46.124-.46.302 0 .124.07.23.07.568v2.735c-.194.498-.513.924-.99.924-.62 0-1.01-.533-1.01-1.457 0-2.557 1.576-3.711 2.921-3.711.177 0 .354.035.514.035.177 0 .23-.107.23-.408 0-.462-.337-.746-.815-.746-2.16 0-4.213 1.811-4.213 4.777 0 1.51.726 2.682 2.107 2.682.672 0 1.168-.32 1.522-.728.266.426.744.728 1.363.728 1.523 0 2.231-1.598 2.532-2.77.018-.072.018-.107.018-.125 0-.337-.337-.728-.62-.728-.177 0-.354.16-.425.533-.16.781-.478 1.918-1.186 1.918zm5.116 1.172c1.523 0 2.213-1.598 2.532-2.77 0-.036.018-.072.018-.125 0-.337-.337-.728-.62-.728-.177 0-.354.16-.425.533-.159.781-.46 1.918-1.274 1.918-.478 0-.709-.462-.709-.96 0-1.775.797-3.871.797-4.084.07-.409-.637-.995-.85-.995h-.92c-.177 0-.354 0-.939-.07-.194-.729-.69-.942-1.115-.942-.46 0-.885.32-.885.817 0 .515.319.888.761 1.137-.018.905-.088 2.38-.283 3.09-.16.604.761 1.243.991.497.319-1.03.425-2.575.443-3.268h1.54c-.566 1.528-.885 2.789-.885 3.925 0 1.563.991 2.025 1.823 2.025zm1.576-.781c0 .657.496.781.85.781.513 0 .496-.426.496-.764V11.18c.124-1.403 1.221-2.93 1.735-2.93.336 0 .371.462.371 1.012v3.606c0 .905.55 1.67 1.487 1.67 1.523 0 2.275-1.6 2.576-2.772.018-.07.018-.106.018-.124 0-.337-.336-.728-.62-.728-.177 0-.354.16-.424.533-.16.781-.523 1.918-1.23 1.918-.461 0-.461-.657-.461-.817V8.87c0-.817-.283-1.793-1.47-1.793-.867 0-1.504.763-1.982 1.758v-.8c0-.426-.372-.78-.956-.78-.248 0-.46.124-.46.301 0 .124.07.231.07.568v5.63zM11.463 0c6.33 0 11.464 5.15 11.464 11.5S17.792 23 11.463 23C5.134 23 0 17.85 0 11.5S5.134 0 11.463 0z' fill='%23397FB1'/%3E%3Cpath d='M19.157 14.802c-.08-.626-.608-1.058-1.287-1.05-1.014.014-1.865.539-2.43.887-.22.136-.41.238-.572.313a4.677 4.677 0 0 0-.26-1.917c-.322-.882-.754-1.424-1.063-1.737.357-.52.847-1.278 1.076-2.45.198-1 .136-2.556-.318-3.428a.702.702 0 0 0-.44-.357c-.08-.022-.23-.066-.525.017-.445-.92-.6-1.018-.719-1.097a.9.9 0 0 0-.81-.093c-.367.133-.68.485-.975 1.11-.044.093-.084.182-.12.27a3.25 3.25 0 0 0-2.186 1.049c-.092.101-.273.176-.463.246h.005c-.388.137-.565.454-.78 1.027-.3.802.008 1.591.312 2.102-.414.37-.965.96-1.256 1.653a5.255 5.255 0 0 0-.388 2.146c-.309.326-.785.939-.838 1.626-.07.96.278 1.613.432 1.85.045.071.093.129.146.186a1.022 1.022 0 0 0 .551 1.097c.582.309 1.393.441 2.02.128.224.238.634.467 1.379.467h.044c.19 0 2.597-.128 3.298-.3.313-.074.529-.207.67-.326.45-.14 1.693-.564 2.865-1.322.83-.537 1.116-.652 1.733-.802.6-.145.974-.692.9-1.295zm-1.05.648c-.704.167-1.062.321-1.934.89-1.363.881-2.853 1.29-2.853 1.29s-.123.186-.48.27c-.617.15-2.94.277-3.152.282-.569.004-.917-.146-1.014-.38-.296-.704.423-1.013.423-1.013s-.159-.097-.251-.185c-.084-.084-.172-.251-.199-.19-.11.27-.167.926-.463 1.221-.405.41-1.172.274-1.626.036-.499-.265.035-.886.035-.886s-.269.158-.485-.168c-.194-.3-.375-.81-.326-1.44.053-.719.855-1.415.855-1.415s-.141-1.062.322-2.15c.419-.992 1.547-1.79 1.547-1.79s-.948-1.049-.595-1.992c.23-.617.322-.612.397-.639.264-.101.52-.211.71-.419.947-1.022 2.155-.828 2.155-.828s.573-1.74 1.102-1.401c.164.105.75 1.41.75 1.41s.626-.366.696-.23c.38.737.424 2.142.256 2.997-.282 1.41-.987 2.168-1.27 2.644-.066.11.759.459 1.279 1.9.48 1.317.053 2.424.128 2.547l.017.03s.552.045 1.658-.638c.59-.366 1.292-.776 2.09-.785.771-.013.81.89.229 1.032z' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E"); 274 | width: 52px; 275 | height: 23px; 276 | } 277 | 278 | .sct__link--npm { 279 | color: #D84848; 280 | } 281 | 282 | .sct__link--npm::before { 283 | background-image: url("data:image/svg+xml,%3Csvg width='42' height='16' viewBox='0 0 42 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill-rule='nonzero' fill='none'%3E%3Cpath fill='%23CB3837' d='M0 0v13.714h11.429V16h9.142v-2.286h20.572V0'/%3E%3Cpath fill='%23FFF' d='M2.286 2.286v9.143h4.571V4.57h2.286v6.858h2.286V2.286h2.285v11.428h4.572V4.571h2.285v4.572h-2.285v2.286h4.571V2.286h2.286v9.143h4.571V4.57H32v6.858h2.286V4.57h2.285v6.858h2.286V2.286'/%3E%3C/g%3E%3C/svg%3E"); 284 | width: 42px; 285 | height: 16px; 286 | } 287 | 288 | .sct__table { 289 | display: -webkit-box; 290 | display: -ms-flexbox; 291 | display: flex; 292 | -ms-flex-wrap: wrap; 293 | flex-wrap: wrap; 294 | margin: 30px 0 50px; 295 | -webkit-box-orient: vertical; 296 | -webkit-box-direction: normal; 297 | -ms-flex-direction: column; 298 | flex-direction: column; 299 | } 300 | 301 | @media all and (max-width: 980px) { 302 | 303 | 304 | .sct__table label { 305 | display: block; 306 | } 307 | } 308 | 309 | .sct__table-cell { 310 | padding: 30px 0; 311 | font-size: 18px; 312 | color: #666A75; 313 | letter-spacing: 0.08px; 314 | } 315 | 316 | .sct__table-cell:not(:last-of-type) { 317 | border-bottom: 1px solid #2E3342; 318 | } 319 | 320 | @media all and (max-width: 980px) { 321 | 322 | 323 | .sct__table-cell { 324 | padding: 20px 0 !important; 325 | } 326 | } 327 | 328 | .sct__table-cell code { 329 | display: block; 330 | white-space: pre; 331 | margin-top: 20px; 332 | font-size: 15px; 333 | color: #C2C4D1; 334 | letter-spacing: -0.49px; 335 | line-height: 20px; 336 | font-family: monospace, monospace; 337 | } 338 | 339 | @media all and (max-width: 980px) { 340 | 341 | 342 | .sct__table-cell code { 343 | font-size: 13px; 344 | max-width: 100%; 345 | overflow-x: auto; 346 | } 347 | } 348 | 349 | @supports (display: grid) { 350 | 351 | 352 | @media all and (min-width: 981px) { 353 | 354 | 355 | .sct__table { 356 | display: grid; 357 | grid-template-columns: repeat(2, 1fr); 358 | grid-gap: 1px; 359 | grid-auto-rows: minmax(150px, auto); 360 | background: #2E3342; 361 | } 362 | } 363 | 364 | 365 | @media all and (min-width: 981px) and all and (max-width: 980px) { 366 | 367 | 368 | .sct__table { 369 | display: block; 370 | background: transparent; 371 | } 372 | } 373 | 374 | 375 | @media all and (min-width: 981px) { 376 | 377 | 378 | .sct__table-cell { 379 | border: 0 !important; 380 | padding: 35px; 381 | background: #23242C; 382 | 383 | /* left side */ 384 | } 385 | 386 | 387 | .sct__table-cell:nth-of-type(2n+1) { 388 | padding-left: 0; 389 | } 390 | 391 | 392 | .sct__table-cell { 393 | 394 | /*right side*/ 395 | } 396 | 397 | 398 | .sct__table-cell:nth-of-type(2n) { 399 | padding-right: 0; 400 | } 401 | 402 | 403 | .sct__table-cell { 404 | 405 | /*top side*/ 406 | } 407 | 408 | 409 | .sct__table-cell:nth-of-type(1), 410 | .sct__table-cell:nth-of-type(2) { 411 | padding-top: 0; 412 | } 413 | 414 | 415 | .sct__table-cell { 416 | 417 | /*bottom side*/ 418 | } 419 | 420 | 421 | .sct__table-cell:nth-last-of-type(1), 422 | .sct__table-cell:nth-last-of-type(2) { 423 | padding-bottom: 0; 424 | } 425 | } 426 | } 427 | 428 | .sct__table-cell .sct__button { 429 | float: right; 430 | margin-top: -0.5em; 431 | } 432 | 433 | @media all and (max-width: 980px) { 434 | 435 | 436 | .sct__table-cell .sct__button { 437 | float: none; 438 | margin-top: 15px; 439 | } 440 | } 441 | 442 | .sct__colors { 443 | float: right; 444 | margin-top: -0.2em; 445 | } 446 | 447 | @media all and (max-width: 980px) { 448 | 449 | 450 | .sct__colors { 451 | float: none; 452 | display: block; 453 | margin-top: 15px; 454 | } 455 | } 456 | 457 | .sct__colors-item { 458 | display: inline-block; 459 | width: 22px; 460 | height: 22px; 461 | border-radius: 3px; 462 | background: #F86464; 463 | margin-left: 8px; 464 | margin-top: -3px; 465 | vertical-align: middle; 466 | cursor: pointer; 467 | } 468 | 469 | @media all and (max-width: 980px) { 470 | 471 | 472 | .sct__colors-item { 473 | margin-left: 0; 474 | margin-right: 10px; 475 | width: 30px; 476 | height: 30px; 477 | } 478 | } 479 | 480 | .sct__colors-item--blue { 481 | background: #519AFF; 482 | } 483 | 484 | .sct__colors-item--yellow { 485 | background: #F3FF6F; 486 | } 487 | 488 | .sct__colors-item--green { 489 | background: #62FF99; 490 | } 491 | 492 | .sct__colors-item--pink { 493 | background: #FFC5FA; 494 | } 495 | 496 | .sct__colors input { 497 | background: rgba(0, 0, 0, .20); 498 | -webkit-box-shadow: inset 0 4px 4px 0 rgba(0, 0, 0, .16); 499 | box-shadow: inset 0 4px 4px 0 rgba(0, 0, 0, .16); 500 | border-radius: 3px; 501 | font-size: 12px; 502 | color: rgba(255, 255, 255, .3); 503 | letter-spacing: 1.1px; 504 | border: 0; 505 | outline: none; 506 | width: 81px; 507 | line-height: 31px; 508 | height: 31px; 509 | text-align: center; 510 | vertical-align: middle; 511 | margin-top: -3px; 512 | } 513 | 514 | .sct__docs { 515 | font-size: 18px; 516 | letter-spacing: 0.15px; 517 | color: #666A75; 518 | } 519 | 520 | .sct__docs a { 521 | color: #99A1AE; 522 | } 523 | 524 | .sct__how p { 525 | max-width: 565px; 526 | font-size: 15.9px; 527 | color: #666A75; 528 | letter-spacing: 0.24px; 529 | line-height: 22px; 530 | } 531 | 532 | .sct__gifs { 533 | display: -webkit-box; 534 | display: -ms-flexbox; 535 | display: flex; 536 | -webkit-box-pack: justify; 537 | -ms-flex-pack: justify; 538 | justify-content: space-between; 539 | margin-top: 35px; 540 | } 541 | 542 | @media all and (max-width: 980px) { 543 | 544 | 545 | .sct__gifs { 546 | -webkit-box-orient: vertical; 547 | -webkit-box-direction: normal; 548 | -ms-flex-direction: column; 549 | flex-direction: column; 550 | } 551 | } 552 | 553 | .sct__gifs-item { 554 | width: 47%; 555 | } 556 | 557 | .sct__gifs-item video { 558 | max-width: 100%; 559 | } 560 | 561 | @media all and (max-width: 980px) { 562 | 563 | 564 | .sct__gifs-item { 565 | width: 100%; 566 | height: 65vw; 567 | } 568 | } 569 | 570 | @media all and (max-width: 980px) { 571 | 572 | 573 | .sct__gifs-item:not(:last-of-type) { 574 | margin-bottom: 20px; 575 | } 576 | } 577 | 578 | .sct__footer { 579 | display: -webkit-box; 580 | display: -ms-flexbox; 581 | display: flex; 582 | border-top: 1px solid rgba(255, 255, 255, .1); 583 | margin-top: 50px; 584 | color: #666A75; 585 | font-size: 14.4px; 586 | padding: 20px 0; 587 | line-height: 1.45em; 588 | } 589 | 590 | @media all and (max-width: 980px) { 591 | 592 | 593 | .sct__footer { 594 | -ms-flex-wrap: wrap; 595 | flex-wrap: wrap; 596 | } 597 | } 598 | 599 | .sct__footer a { 600 | color: #99A1AE; 601 | text-decoration: none; 602 | } 603 | 604 | .sct__footer-right { 605 | margin-left: auto; 606 | } 607 | 608 | @media all and (max-width: 980px) { 609 | 610 | 611 | .sct__footer-right { 612 | margin-top: 15px; 613 | -ms-flex-preferred-size: 100%; 614 | flex-basis: 100%; 615 | } 616 | } 617 | 618 | /** 619 | * Highlighted code 620 | */ 621 | .hcode--keyword { 622 | color: #7e869b; 623 | } 624 | .hcode--object { 625 | color: #a2abc1; 626 | } 627 | .hcode--method { 628 | color: #787c90; 629 | } 630 | .hcode--property { 631 | color: #85869b; 632 | } 633 | .hcode--string { 634 | color: #77b188; 635 | } 636 | .hcode--number { 637 | color: #4ba2d1; 638 | } 639 | --------------------------------------------------------------------------------