├── .gitignore ├── .editorconfig ├── .travis.yml ├── license ├── package.json ├── readme.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 4 5 | indent_style = space 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | 9 | [*.{json,yml,yaml}] 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "11" 5 | - "10" 6 | - "8" 7 | 8 | cache: npm 9 | 10 | install: npm ci 11 | 12 | before_script: 13 | - npm run lint 14 | 15 | branches: 16 | only: 17 | - master 18 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Arnelle Balane 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mdi-cli", 3 | "version": "1.4.0", 4 | "description": "Generate material design icons from the command line", 5 | "main": "index.js", 6 | "bin": { 7 | "mdi": "index.js" 8 | }, 9 | "scripts": { 10 | "commit": "git-cz", 11 | "lint": "eslint *.js" 12 | }, 13 | "keywords": [ 14 | "mdi", 15 | "material-design", 16 | "icons", 17 | "cli" 18 | ], 19 | "files": [ 20 | "index.js" 21 | ], 22 | "author": "Arnelle Balane (https://arnellebalane.com/)", 23 | "license": "MIT", 24 | "dependencies": { 25 | "@mdi/svg": "3.0.39", 26 | "chalk": "2.4.1", 27 | "fuse.js": "3.3.0", 28 | "inquirer": "6.2.0", 29 | "inquirer-checkbox-plus-prompt": "1.0.1", 30 | "mdi-core": "1.1.0", 31 | "meow": "5.0.0", 32 | "ora": "3.0.0" 33 | }, 34 | "devDependencies": { 35 | "commitizen": "3.0.4", 36 | "cz-conventional-changelog": "2.1.0", 37 | "eslint": "5.9.0", 38 | "eslint-config-arnellebalane": "3.3.0", 39 | "ghooks": "2.0.4" 40 | }, 41 | "config": { 42 | "commitizen": { 43 | "path": "cz-conventional-changelog" 44 | }, 45 | "ghooks": { 46 | "pre-commit": "npm run lint" 47 | } 48 | }, 49 | "eslintConfig": { 50 | "extends": [ 51 | "arnellebalane" 52 | ], 53 | "parserOptions": { 54 | "ecmaVersion": 2017 55 | }, 56 | "env": { 57 | "node": true, 58 | "es6": true 59 | }, 60 | "rules": { 61 | "max-len": [ 62 | "off" 63 | ] 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

2 | mdi-cli icon 3 |

4 | 5 | # mdi-cli 6 | 7 | Generate material design icons from the command line. 8 | 9 | All icons are based on the [@mdi/svg][1] package, which is what [materialdesignicons.com][2] uses. 10 | 11 | ## Installation 12 | 13 | `mdi-cli` can be installed using `npm` by running: 14 | 15 | ```bash 16 | $ npm install -g mdi-cli 17 | ``` 18 | 19 | 20 | ## Usage 21 | 22 | Installing this package globally will give you the `mdi` command. The GIF below shows how to use it interactively: 23 | 24 | ![Usage Example](https://cdn.arnellebalane.com/github/mdi-cli/example.gif) 25 | 26 | You may also use `mdi` non-interactively, by providing flags and arguments when you run it: 27 | 28 | ```bash 29 | $ mdi --help 30 | 31 | Generate material design icons from the command line 32 | 33 | Usage: 34 | $ mdi [options] , , ... 35 | 36 | Options: 37 | --size, -s Set the icon size. Defaults to 24px. 38 | --padding, -p Set the icon padding. Defaults to 0px. 39 | --radius, -r Set the icon border radius. Defaults to 0px. 40 | --foreground, -f Set the icon foreground color. Defaults to #333. 41 | --background, -b Set the icon background color. Defaults to transparent. 42 | --output, -o Write icons to this directory. Defaults to the current directory. 43 | 44 | Examples: 45 | $ mdi -s 32 -p 4 -r 5 -f yellow -b black google youtube twitter 46 | ``` 47 | 48 | 49 | ## Why did I build this? 50 | 51 | [materialdesignicons.com][2] is cool, I like using it because 52 | 53 | 1. I can see what the actual icons look like 54 | 2. I can easily resize and set padding of the icon and see the results 55 | 56 | However, I usually get several icons with the same styles at the same time, and doing so always takes so much time. 57 | 58 | This tool allows: 59 | 60 | 1. Generating multiple icons with the same style 61 | 2. Generating icons even when you're offline 62 | 63 | However, this also comes with its own limitations: 64 | 65 | 1. No icon preview while generating, so you kinda have to know the names of the icons that you need 66 | 67 | 68 | ## Related Projects 69 | 70 | - [mdi-core][3]: Node module for generating Material Design icons. 71 | 72 | 73 | ## License 74 | 75 | MIT License 76 | 77 | 78 | [1]: https://github.com/Templarian/MaterialDesign-SVG 79 | [2]: https://materialdesignicons.com/ 80 | [3]: https://github.com/arnellebalane/mdi-core 81 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const inquirer = require('inquirer'); 3 | const icons = require('@mdi/svg/meta.json'); 4 | const Fuse = require('fuse.js'); 5 | const chalk = require('chalk'); 6 | const ora = require('ora'); 7 | const meow = require('meow'); 8 | const mdi = require('mdi-core'); 9 | 10 | inquirer.registerPrompt('checkbox-plus', require('inquirer-checkbox-plus-prompt')); 11 | 12 | const fuse = new Fuse(icons, { 13 | shouldSort: true, 14 | threshold: 0, 15 | keys: ['name', 'aliases'] 16 | }); 17 | const spinner = ora('Generating icons'); 18 | 19 | const cli = meow(` 20 | ${chalk.cyan.underline('Usage:')} 21 | ${chalk.gray('$')} ${chalk.green('mdi')} ${chalk.yellow('[options]')} ${chalk.magenta(' ...')} 22 | 23 | ${chalk.cyan.underline('Options:')} 24 | ${chalk.yellow('--size')}, ${chalk.yellow('-s')} ${chalk.gray('Set the icon size. Defaults to 24px.')} 25 | ${chalk.yellow('--padding')}, ${chalk.yellow('-p')} ${chalk.gray('Set the icon padding. Defaults to 0px.')} 26 | ${chalk.yellow('--radius')}, ${chalk.yellow('-r')} ${chalk.gray('Set the icon border radius. Defaults to 0px.')} 27 | ${chalk.yellow('--foreground')}, ${chalk.yellow('-f')} ${chalk.gray('Set the icon foreground color. Defaults to #333.')} 28 | ${chalk.yellow('--background')}, ${chalk.yellow('-b')} ${chalk.gray('Set the icon background color. Defaults to transparent.')} 29 | ${chalk.yellow('--output')}, ${chalk.yellow('-o')} ${chalk.gray('Write icons to this directory. Defaults to the current directory.')} 30 | 31 | ${chalk.cyan.underline('Examples:')} 32 | ${chalk.gray('$')} ${chalk.green('mdi')} ${chalk.yellow('-s 32 -p 4 -r 5 -f #aaa -b #fff')} ${chalk.magenta('google youtube twitter')} 33 | `, { 34 | flags: { 35 | size: { 36 | type: 'string', 37 | alias: 's', 38 | default: '24' 39 | }, 40 | padding: { 41 | type: 'string', 42 | alias: 'p', 43 | default: '0' 44 | }, 45 | radius: { 46 | type: 'string', 47 | alias: 'r', 48 | default: '0' 49 | }, 50 | foreground: { 51 | type: 'string', 52 | alias: 'f', 53 | default: '#333' 54 | }, 55 | background: { 56 | type: 'string', 57 | alias: 'b', 58 | default: 'transparent' 59 | }, 60 | output: { 61 | type: 'string', 62 | alias: 'o', 63 | default: '.' 64 | } 65 | }, 66 | inferType: true 67 | }); 68 | 69 | const promptOptions = [{ 70 | type: 'checkbox-plus', 71 | name: 'names', 72 | message: 'Icon names:', 73 | source(answers, input) { 74 | return input 75 | ? Promise.resolve(fuse.search(input)) 76 | : Promise.resolve(icons.map(icon => icon.name)); 77 | }, 78 | searchable: true 79 | }, { 80 | type: 'input', 81 | name: 'size', 82 | message: 'Icon size (px):', 83 | default: 24, 84 | filter: Number 85 | }, { 86 | type: 'input', 87 | name: 'padding', 88 | message: 'Icon padding (px):', 89 | default: 0, 90 | filter: Number 91 | }, { 92 | type: 'input', 93 | name: 'radius', 94 | message: 'Border radius (px):', 95 | default: 0, 96 | filter: Number 97 | }, { 98 | type: 'input', 99 | name: 'foreground', 100 | message: 'Foreground color:', 101 | default: '#333' 102 | }, { 103 | type: 'input', 104 | name: 'background', 105 | message: 'Background color:', 106 | default: 'transparent' 107 | }, { 108 | type: 'input', 109 | name: 'output', 110 | message: 'Output path:', 111 | default: 'current directory', 112 | filter(input) { 113 | return input === 'current directory' ? '.' : input; 114 | } 115 | }]; 116 | 117 | (async function() { 118 | const useBuilder = process.argv.length === 2; 119 | const config = useBuilder 120 | ? await inquirer.prompt(promptOptions) 121 | : cli.flags; 122 | if (!useBuilder) { 123 | config.names = cli.input; 124 | } 125 | 126 | spinner.start(); 127 | const iconPaths = await mdi(config); 128 | spinner.stop(); 129 | 130 | // Add an extra separator line 131 | console.log(); 132 | iconPaths.forEach(iconPath => { 133 | console.log(` Generated ${chalk.green(iconPath)}`); 134 | }); 135 | })(); 136 | --------------------------------------------------------------------------------