├── .babelrc ├── .eslintrc ├── .gitignore ├── README.md ├── package.json ├── scripts.js ├── src ├── index.html ├── scripts.js └── styles.scss └── styles.css /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "rules": { 4 | "indent": ["error", 2, { "SwitchCase": 1 }], 5 | "no-console": 0, 6 | "semi": ["error", "always"] 7 | }, 8 | "globals": { 9 | "window": true, 10 | "define": true, 11 | "$": true 12 | }, 13 | "env": { 14 | "node": true, 15 | "browser": true, 16 | "es6": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Caniuse Component 2 | 3 | Instant, up-to-date, and theme-able browser statistics for your presentations (so you don't have to update your slides the night before!) 4 | 5 | ### [Here is a Demo 😄](https://una.im/caniuse-component/) 6 | 7 | - customizable style based on a variable system 8 | - adaptive text color based on background [source](https://codepen.io/una/pen/oXgRYz) 9 | - automatic browser logos & caniuse data 10 | - not compatible with IE 6/7 11 | 12 | ## Usage 13 | 14 | ### Node Implementation 15 | 16 | Install via NPM: `npm install caniuse-component` -- include the js and css source. 17 | 18 | ### Reveal.js Implementation 19 | 20 | To use this with [Reveal.js](https://github.com/hakimel/reveal.js/), npm install, then apply this source as a plugin: 21 | 22 | ``` 23 | Reveal.initialize({ 24 | // setup things here: 25 | // ... 26 | 27 | // plugins here: 28 | dependencies: [ 29 | { src: '../node_modules/caniuse-component/scripts.js', async: true }, 30 | { src: '../node_modules/caniuse-component/styles.css' } 31 | ] 32 | }); 33 | ``` 34 | 35 | Then, include this element on your page: 36 | 37 | ``` 38 | 42 | ``` 43 | 44 | | name | function | usage | options | 45 | |--- |--- |--- |--- | 46 | | **id** | Applies styles to list | `id="caniuse--result-list"` | You only get one option unless you make your own | 47 | | **propName** | CSS Property Name | `data-propName="css-filters"` | See [Caniuse API](https://github.com/nyalab/caniuse-api) and [options](https://github.com/Fyrd/caniuse/tree/master/features-json) | 48 | | **browsers** | Browsers to check support from | `data-browsers="firefox chrome safari"` | `edge`, `chrome`, `safari`, `ie`, `firefox`, `opera` | 49 | 50 | 51 | ## Development & Contribution 52 | 53 | NPM scripts are used as the build system, so to develop, run: `npm run dev`. Consumable files are distributed in the root, and source files live within `/src`. 54 | 55 | To contribute: Please clone this down and submit a PR, or open an issue. 😘 56 | 57 | ## Credits 58 | 59 | - [Caniuse API](https://github.com/nyalab/caniuse-api) 60 | - [Browser Logos](https://github.com/alrra/browser-logos/) 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "caniuse-component", 3 | "version": "0.1.5", 4 | "description": "Up-to-date caniuse.com data for your slides", 5 | "main": "./scripts.js", 6 | "scripts": { 7 | "js": "watchify src/scripts.js -t babelify --outfile ./scripts.js", 8 | "compile-js": "babel src/scripts.js --out-file ./scripts.js", 9 | "styles": "node-sass -w src/ -o ./ --output-style compressed", 10 | "dev": "npm run js & npm run styles" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/una/caniuse-component.git" 15 | }, 16 | "keywords": [ 17 | "reveal.js", 18 | "presentation", 19 | "caniuse", 20 | "plugin" 21 | ], 22 | "author": "Una Kravets", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/una/caniuse-component/issues" 26 | }, 27 | "homepage": "https://github.com/una/caniuse-component#readme", 28 | "dependencies": { 29 | "caniuse-api": "^2.0.0", 30 | "reveal.js": "^3.4.1" 31 | }, 32 | "devDependencies": { 33 | "babel-cli": "^6.24.0", 34 | "babel-preset-es2015": "^6.24.0", 35 | "babelify": "^8.0.0", 36 | "watchify": "^3.9.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Caniuse Component 6 | 7 | 8 | 9 | 10 | 11 | 25 | 26 |
27 |

Browser Support: CSS Grid

28 | 29 | 30 |
31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/scripts.js: -------------------------------------------------------------------------------- 1 | const caniuse = require('caniuse-api'); 2 | const DOMContainer = document.querySelector('#caniuse--result-list'); 3 | const defaultIcon = " "; 4 | 5 | class ResultBlock { 6 | constructor(name) { 7 | this.name = name; 8 | } 9 | 10 | supportCall() { 11 | return caniuse.getSupport(this.name); 12 | } 13 | 14 | browserResults(browsers) { 15 | 16 | // iterate through each browser and show its support via caniuse info: 17 | // y: Since which browser version the feature is available 18 | // n: Up to which browser version the feature is unavailable 19 | // a: Up to which browser version the feature is partially supported 20 | // X: Up to which browser version the feature is prefixed 21 | for (let browser of browsers) { 22 | const browserName = browser; 23 | let returnedResult, supportLevel; 24 | let isPrefixed = false; 25 | const supportResults = this.supportCall()[browser]; 26 | 27 | if (supportResults.y) { // its supported 28 | supportLevel = 'full'; 29 | returnedResult = supportResults.y + '+'; 30 | 31 | if (supportResults.a) { 32 | supportLevel = 'partial'; 33 | } 34 | 35 | if (supportResults.x) { 36 | isPrefixed = true; 37 | } 38 | } else { 39 | supportLevel = 'none'; 40 | returnedResult = 'no support'; 41 | } 42 | 43 | this.buildBlock(browserName, returnedResult, supportLevel, isPrefixed); 44 | } 45 | } 46 | 47 | buildBlock(browserName, publishedResult, supportLevel, isPrefixed) { 48 | let prefixMsg; 49 | 50 | // IE rewrites 51 | if (browserName === 'ie') { 52 | browserName = 'internet-explorer'; 53 | } 54 | 55 | // check if theres a level of support 56 | function supportText(supportLevel) { 57 | if (supportLevel != 'none') { 58 | return `

${supportLevel}

`; 59 | } else return ''; 60 | } 61 | 62 | // check if there is a prefix 63 | function prefixText(isPrefixed) { 64 | if (isPrefixed) { 65 | // these should be switch statements 66 | if (browserName === 'chrome' || browserName === 'safari') { 67 | prefixMsg = '-webkit-'; 68 | } 69 | else if (browserName === 'firefox') { 70 | prefixMsg = '-moz-'; 71 | } 72 | else if (browserName === 'edge' || browserName === 'ie') { 73 | prefixMsg = '-ms-'; 74 | } 75 | else if (browserName === 'opera') { 76 | prefixMsg = '-o-'; 77 | } 78 | 79 | return `

${prefixMsg}

`; 80 | } else { 81 | if (supportLevel != 'none') { 82 | return `

no prefix

`; 83 | } else { 84 | return ''; 85 | } 86 | } 87 | } 88 | 89 | DOMContainer.innerHTML += 90 | `
  • 91 | 92 |

    ${browserName.replace(/-/g, ' ').replace(/(^|\s)[a-z]/g, (f) => {return f.toUpperCase();})}

    93 |

    ${publishedResult}

    94 | ${supportText(supportLevel)} 95 | ${prefixText(isPrefixed)} 96 |
  • `; 97 | } 98 | } 99 | 100 | // Read the DOM and initiate based on data props 101 | document.onreadystatechange = () => { 102 | if (document.readyState === 'complete') { 103 | const name = DOMContainer.getAttribute('data-propName'); 104 | const browsers = DOMContainer.getAttribute('data-browsers').split(' '); 105 | new ResultBlock(name, true).browserResults(browsers); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | $color--warn: #f1dc99; // partial support 2 | $color--success: #a2e9c1; // full support 3 | $color--error: #ffa5a5; // no support 4 | $color--text--light: #fff; // text color on dark backgrounds 5 | $color--text--dark: #000; // text color on light backgrounds 6 | 7 | $font__browser--size: 32px; 8 | $font__version--size: 24px; 9 | $font__meta--size: 18px; 10 | $border-radius: 2px; 11 | $li-margin: 10px; 12 | $icon-width: 120px; 13 | 14 | // Text Contrast Mixin 15 | // Determines font color based 16 | // on background color 17 | $contrast-settings: ( 18 | 'light-color': $color--text--light, 19 | 'dark-color': $color--text--dark 20 | ); 21 | 22 | @mixin contrast-me($bg-color) { 23 | @if lightness($bg-color) < 40% { 24 | color: map-get($contrast-settings, 'light-color'); 25 | } @else { 26 | color: map-get($contrast-settings, 'dark-color'); 27 | } 28 | 29 | background-color: $bg-color; 30 | } 31 | 32 | #caniuse--result-list { 33 | display: flex; 34 | flex-wrap: wrap; 35 | font-family: inherit; 36 | margin: 0; 37 | padding: 0; 38 | 39 | li { 40 | border-radius: $border-radius; 41 | flex: 1; 42 | list-style: none; 43 | margin: $li-margin; 44 | padding: $li-margin; 45 | text-align: center; 46 | } 47 | 48 | .caniuse { 49 | &--browser-img { 50 | height: $icon-width; 51 | margin: $li-margin * 2 auto 0; 52 | width: $icon-width; 53 | } 54 | 55 | &--browser-name { 56 | font-size: $font__browser--size; 57 | line-height: 1; 58 | } 59 | 60 | &--browser-results { 61 | font-size: $font__version--size; 62 | line-height: 0; 63 | } 64 | 65 | &--support-level { 66 | font-size: $font__meta--size; 67 | } 68 | } 69 | 70 | .support--partial { 71 | @include contrast-me($color--warn); 72 | } 73 | 74 | .support--full { 75 | @include contrast-me($color--success); 76 | } 77 | 78 | .support--none { 79 | @include contrast-me($color--error); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | #caniuse--result-list{display:flex;flex-wrap:wrap;font-family:inherit;margin:0;padding:0}#caniuse--result-list li{border-radius:2px;flex:1;list-style:none;margin:10px;padding:10px;text-align:center}#caniuse--result-list .caniuse--browser-img{height:120px;margin:20px auto 0;width:120px}#caniuse--result-list .caniuse--browser-name{font-size:32px;line-height:1}#caniuse--result-list .caniuse--browser-results{font-size:24px;line-height:0}#caniuse--result-list .caniuse--support-level{font-size:18px}#caniuse--result-list .support--partial{color:#000;background-color:#f1dc99}#caniuse--result-list .support--full{color:#000;background-color:#a2e9c1}#caniuse--result-list .support--none{color:#000;background-color:#ffa5a5} 2 | --------------------------------------------------------------------------------