├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── app.js ├── data.json ├── gulpfile.js ├── now.json ├── package-lock.json ├── package.json ├── public ├── icons │ ├── android-chrome-192x192.png │ ├── android-chrome-256x256.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── heart.png │ ├── mstile-150x150.png │ ├── safari-pinned-tab.svg │ └── site.webmanifest ├── index.html └── index.js ├── src ├── js │ ├── copy-to-clipboard.js │ ├── country-names-switcher.js │ └── generate-output.js ├── pug │ ├── badge-generator.pug │ ├── head.pug │ └── index.pug └── styl │ ├── badge-generator.styl │ ├── base.styl │ ├── index.styl │ └── universal.styl └── static └── pt.svg /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | block_comment_start = /* 11 | block_comment = * 12 | block_comment_end = */ 13 | 14 | [*.md] 15 | indent_style = space 16 | indent_size = 4 17 | trim_trailing_whitespace = false 18 | 19 | [{*.json,*.yml,*.toml}] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | # Excluded files 24 | [LICENSE] 25 | charset = unset 26 | end_of_line = unset 27 | insert_final_newline = unset 28 | trim_trailing_whitespace = unset 29 | indent_style = unset 30 | indent_size = unset 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Custom 2 | public/index.css 3 | 4 | # Created by https://www.gitignore.io/api/node 5 | # Edit at https://www.gitignore.io/?templates=node 6 | 7 | ### Node ### 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # Optional npm cache directory 50 | .npm 51 | 52 | # Optional eslint cache 53 | .eslintcache 54 | 55 | # Optional REPL history 56 | .node_repl_history 57 | 58 | # Output of 'npm pack' 59 | *.tgz 60 | 61 | # Yarn Integrity file 62 | .yarn-integrity 63 | 64 | # dotenv environment variables file 65 | .env 66 | .env.test 67 | 68 | # parcel-bundler cache (https://parceljs.org/) 69 | .cache 70 | 71 | # next.js build output 72 | .next 73 | 74 | # nuxt.js build output 75 | .nuxt 76 | 77 | # vuepress build output 78 | .vuepress/dist 79 | 80 | # Serverless directories 81 | .serverless/ 82 | 83 | # FuseBox cache 84 | .fusebox/ 85 | 86 | # DynamoDB Local files 87 | .dynamodb/ 88 | 89 | # End of https://www.gitignore.io/api/node 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, Mihir Chaturvedi 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | 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, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Made with ❤️ in `country-name` 2 | 3 | ![Made with love in India](https://madewithlove.now.sh/in?heart=true&template=for-the-badge) 4 | 5 | > A microservice for serving and listing the "Made with love in" badge. 6 | 7 | Provides a quick and easy way to add the "Made with love in `country-name`" badge to show off your project's country of origin! 8 | 9 | Go to [madewithlove.now.sh](https://madewithlove.now.sh) to generate your own badge 🙂. 10 | 11 | ## About 12 | 13 | I built this project primarily to understand how to implement small-scale and simple APIs (microservices), especially using [now.sh](https://now.sh) and it's serverless deployments. 14 | 15 | Also, I believe this is a cute way to show where you are from or where you built your project, so yeah. 16 | 17 | Initial inspiration for the project came from [https://madewithlove.org.in](https://madewithlove.org.in). Badges are generated by [Shields.io](https://shields.io): the code is essentially a wrapper around their [gh-badges](https://www.npmjs.com/package/gh-badges) library. 18 | 19 | ## Usage 20 | 21 | ``` 22 | GET /list 23 | GET /:countryCode 24 | 25 | e.g. GET /in 26 | GET /gb?heart=true&flag=true 27 | GET /us?colorA=lightgreen&colorB=red&text=USA 28 | ``` 29 | --- 30 | 31 | ## License 32 | 33 | Copyright (c) Mihir Chaturvedi. All rights reserved. 34 | 35 | Licensed under the [MIT](LICENSE) License. 36 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fastify = require('fastify')(); 3 | const {BadgeFactory} = require('gh-badges'); 4 | const DATA = require('./data.json'); 5 | 6 | fastify.register(require('fastify-static'), { 7 | root: path.join(__dirname, 'public'), 8 | prefix: '/public/', 9 | }) 10 | 11 | fastify.get('/', (req, reply) => { 12 | return reply.sendFile('index.html'); 13 | }); 14 | 15 | fastify.get('/index.js', (req, reply) => { 16 | return reply.sendFile('index.js'); 17 | }); 18 | 19 | fastify.get('/list', (req, reply) => { 20 | return reply.json(DATA); 21 | }); 22 | 23 | fastify.get('/:countryCode', (req, reply) => { 24 | let {countryCode} = req.params; 25 | countryCode = countryCode.toLowerCase(); 26 | 27 | if (!(countryCode in DATA)) { 28 | reply.status(400); 29 | return reply.send(`
Error 400: country code "${countryCode}" not found.\nGET /list for list of valid country codes.
`); 30 | } 31 | 32 | const config = { 33 | heart: false, 34 | ...req.query 35 | }; 36 | 37 | const countryName = DATA[countryCode.toLowerCase()]; 38 | const countryText = 'text' in config ? config.text : countryName; 39 | 40 | const badgeFormat = { 41 | template: 'flat', 42 | colorB: '#dc3545', 43 | ...config, 44 | text: [ 45 | `Made with ${config.heart ? '❤' : 'love'} in`, 46 | countryText 47 | ] 48 | }; 49 | 50 | const badgeSvg = new BadgeFactory().create(badgeFormat); 51 | 52 | reply.type('image/svg+xml'); 53 | return reply.send(badgeSvg); 54 | }); 55 | 56 | fastify.listen(process.env.PORT || 5000); 57 | -------------------------------------------------------------------------------- /data.json: -------------------------------------------------------------------------------- 1 | { 2 | "ac": "Ascension Island", 3 | "ad": "Andorra", 4 | "ae": "United Arab Emirates", 5 | "af": "Afghanistan", 6 | "ag": "Antigua & Barbuda", 7 | "ai": "Anguilla", 8 | "al": "Albania", 9 | "am": "Armenia", 10 | "ao": "Angola", 11 | "aq": "Antarctica", 12 | "ar": "Argentina", 13 | "as": "American Samoa", 14 | "at": "Austria", 15 | "au": "Australia", 16 | "aw": "Aruba", 17 | "ax": "Åland Islands", 18 | "az": "Azerbaijan", 19 | "ba": "Bosnia & Herzegovina", 20 | "bb": "Barbados", 21 | "bd": "Bangladesh", 22 | "be": "Belgium", 23 | "bf": "Burkina Faso", 24 | "bg": "Bulgaria", 25 | "bh": "Bahrain", 26 | "bi": "Burundi", 27 | "bj": "Benin", 28 | "bl": "St. Barthélemy", 29 | "bm": "Bermuda", 30 | "bn": "Brunei", 31 | "bo": "Bolivia", 32 | "bq": "Caribbean Netherlands", 33 | "br": "Brazil", 34 | "bs": "Bahamas", 35 | "bt": "Bhutan", 36 | "bv": "Bouvet Island", 37 | "bw": "Botswana", 38 | "by": "Belarus", 39 | "bz": "Belize", 40 | "ca": "Canada", 41 | "cc": "Cocos (Keeling) Islands", 42 | "cd": "Congo - Kinshasa", 43 | "cf": "Central African Republic", 44 | "cg": "Congo - Brazzaville", 45 | "ch": "Switzerland", 46 | "ci": "Côte d’Ivoire", 47 | "ck": "Cook Islands", 48 | "cl": "Chile", 49 | "cm": "Cameroon", 50 | "cn": "China", 51 | "co": "Colombia", 52 | "cp": "Clipperton Island", 53 | "cr": "Costa Rica", 54 | "cu": "Cuba", 55 | "cv": "Cape Verde", 56 | "cw": "Curaçao", 57 | "cx": "Christmas Island", 58 | "cy": "Cyprus", 59 | "cz": "Czechia", 60 | "de": "Germany", 61 | "dg": "Diego Garcia", 62 | "dj": "Djibouti", 63 | "dk": "Denmark", 64 | "dm": "Dominica", 65 | "do": "Dominican Republic", 66 | "dz": "Algeria", 67 | "ea": "Ceuta & Melilla", 68 | "ec": "Ecuador", 69 | "ee": "Estonia", 70 | "eg": "Egypt", 71 | "eh": "Western Sahara", 72 | "er": "Eritrea", 73 | "es": "Spain", 74 | "et": "Ethiopia", 75 | "eu": "European Union", 76 | "fi": "Finland", 77 | "fj": "Fiji", 78 | "fk": "Falkland Islands", 79 | "fm": "Micronesia", 80 | "fo": "Faroe Islands", 81 | "fr": "France", 82 | "ga": "Gabon", 83 | "gb": "United Kingdom", 84 | "gd": "Grenada", 85 | "ge": "Georgia", 86 | "gf": "French Guiana", 87 | "gg": "Guernsey", 88 | "gh": "Ghana", 89 | "gi": "Gibraltar", 90 | "gl": "Greenland", 91 | "gm": "Gambia", 92 | "gn": "Guinea", 93 | "gp": "Guadeloupe", 94 | "gq": "Equatorial Guinea", 95 | "gr": "Greece", 96 | "gs": "South Georgia & South Sandwich Islands", 97 | "gt": "Guatemala", 98 | "gu": "Guam", 99 | "gw": "Guinea-Bissau", 100 | "gy": "Guyana", 101 | "hk": "Hong Kong SAR China", 102 | "hm": "Heard & McDonald Islands", 103 | "hn": "Honduras", 104 | "hr": "Croatia", 105 | "ht": "Haiti", 106 | "hu": "Hungary", 107 | "ic": "Canary Islands", 108 | "id": "Indonesia", 109 | "ie": "Ireland", 110 | "il": "Israel", 111 | "im": "Isle of Man", 112 | "in": "India", 113 | "io": "British Indian Ocean Territory", 114 | "iq": "Iraq", 115 | "ir": "Iran", 116 | "is": "Iceland", 117 | "it": "Italy", 118 | "je": "Jersey", 119 | "jm": "Jamaica", 120 | "jo": "Jordan", 121 | "jp": "Japan", 122 | "ke": "Kenya", 123 | "kg": "Kyrgyzstan", 124 | "kh": "Cambodia", 125 | "ki": "Kiribati", 126 | "km": "Comoros", 127 | "kn": "St. Kitts & Nevis", 128 | "kp": "North Korea", 129 | "kr": "South Korea", 130 | "kw": "Kuwait", 131 | "ky": "Cayman Islands", 132 | "kz": "Kazakhstan", 133 | "la": "Laos", 134 | "lb": "Lebanon", 135 | "lc": "St. Lucia", 136 | "li": "Liechtenstein", 137 | "lk": "Sri Lanka", 138 | "lr": "Liberia", 139 | "ls": "Lesotho", 140 | "lt": "Lithuania", 141 | "lu": "Luxembourg", 142 | "lv": "Latvia", 143 | "ly": "Libya", 144 | "ma": "Morocco", 145 | "mc": "Monaco", 146 | "md": "Moldova", 147 | "me": "Montenegro", 148 | "mf": "St. Martin", 149 | "mg": "Madagascar", 150 | "mh": "Marshall Islands", 151 | "mk": "Macedonia", 152 | "ml": "Mali", 153 | "mm": "Myanmar (Burma)", 154 | "mn": "Mongolia", 155 | "mo": "Macau SAR China", 156 | "mp": "Northern Mariana Islands", 157 | "mq": "Martinique", 158 | "mr": "Mauritania", 159 | "ms": "Montserrat", 160 | "mt": "Malta", 161 | "mu": "Mauritius", 162 | "mv": "Maldives", 163 | "mw": "Malawi", 164 | "mx": "Mexico", 165 | "my": "Malaysia", 166 | "mz": "Mozambique", 167 | "na": "Namibia", 168 | "nc": "New Caledonia", 169 | "ne": "Niger", 170 | "nf": "Norfolk Island", 171 | "ng": "Nigeria", 172 | "ni": "Nicaragua", 173 | "nl": "Netherlands", 174 | "no": "Norway", 175 | "np": "Nepal", 176 | "nr": "Nauru", 177 | "nu": "Niue", 178 | "nz": "New Zealand", 179 | "om": "Oman", 180 | "pa": "Panama", 181 | "pe": "Peru", 182 | "pf": "French Polynesia", 183 | "pg": "Papua New Guinea", 184 | "ph": "Philippines", 185 | "pk": "Pakistan", 186 | "pl": "Poland", 187 | "pm": "St. Pierre & Miquelon", 188 | "pn": "Pitcairn Islands", 189 | "pr": "Puerto Rico", 190 | "ps": "Palestinian Territories", 191 | "pt": "Portugal", 192 | "pw": "Palau", 193 | "py": "Paraguay", 194 | "qa": "Qatar", 195 | "re": "Réunion", 196 | "ro": "Romania", 197 | "rs": "Serbia", 198 | "ru": "Russia", 199 | "rw": "Rwanda", 200 | "sa": "Saudi Arabia", 201 | "sb": "Solomon Islands", 202 | "sc": "Seychelles", 203 | "sd": "Sudan", 204 | "se": "Sweden", 205 | "sg": "Singapore", 206 | "sh": "St. Helena", 207 | "si": "Slovenia", 208 | "sj": "Svalbard & Jan Mayen", 209 | "sk": "Slovakia", 210 | "sl": "Sierra Leone", 211 | "sm": "San Marino", 212 | "sn": "Senegal", 213 | "so": "Somalia", 214 | "sr": "Suriname", 215 | "ss": "South Sudan", 216 | "st": "São Tomé & Príncipe", 217 | "sv": "El Salvador", 218 | "sx": "Sint Maarten", 219 | "sy": "Syria", 220 | "sz": "Swaziland", 221 | "ta": "Tristan da Cunha", 222 | "tc": "Turks & Caicos Islands", 223 | "td": "Chad", 224 | "tf": "French Southern Territories", 225 | "tg": "Togo", 226 | "th": "Thailand", 227 | "tj": "Tajikistan", 228 | "tk": "Tokelau", 229 | "tl": "Timor-Leste", 230 | "tm": "Turkmenistan", 231 | "tn": "Tunisia", 232 | "to": "Tonga", 233 | "tr": "Turkey", 234 | "tt": "Trinidad & Tobago", 235 | "tv": "Tuvalu", 236 | "tw": "Taiwan", 237 | "tz": "Tanzania", 238 | "ua": "Ukraine", 239 | "ug": "Uganda", 240 | "um": "U.S. Outlying Islands", 241 | "us": "United States", 242 | "uy": "Uruguay", 243 | "uz": "Uzbekistan", 244 | "va": "Vatican City", 245 | "vc": "St. Vincent & Grenadines", 246 | "ve": "Venezuela", 247 | "vg": "British Virgin Islands", 248 | "vi": "U.S. Virgin Islands", 249 | "vn": "Vietnam", 250 | "vu": "Vanuatu", 251 | "wf": "Wallis & Futuna", 252 | "ws": "Samoa", 253 | "xk": "Kosovo", 254 | "ye": "Yemen", 255 | "yt": "Mayotte", 256 | "za": "South Africa", 257 | "zm": "Zambia", 258 | "zw": "Zimbabwe" 259 | } 260 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const babel = require('gulp-babel'); 3 | const concat = require('gulp-concat'); 4 | const cssnano = require('cssnano'); 5 | const del = require('del'); 6 | const gulp = require('gulp'); 7 | const inlineSource = require('gulp-inline-source'); 8 | const postcss = require('gulp-postcss'); 9 | const pug = require('gulp-pug'); 10 | const stylus = require('gulp-stylus'); 11 | const DATA = require('./data.json'); 12 | 13 | gulp.task('pug', () => { 14 | const nameToCodeMap = {}; 15 | Object.keys(DATA).forEach(key => { 16 | nameToCodeMap[DATA[key]] = key; 17 | }); 18 | 19 | return gulp.src('src/pug/index.pug') 20 | .pipe(pug({ 21 | locals: { 22 | countryNames: nameToCodeMap 23 | } 24 | })) 25 | .pipe(gulp.dest('public/')); 26 | }); 27 | 28 | gulp.task('generateCss', () => { 29 | return gulp.src('src/styl/index.styl') 30 | .pipe(stylus()) 31 | .pipe(postcss([autoprefixer, cssnano])) 32 | .pipe(gulp.dest('public/')); 33 | }); 34 | 35 | gulp.task('inlineCss', () => { 36 | return gulp.src('public/index.html') 37 | .pipe(inlineSource()) 38 | .pipe(gulp.dest('public/')); 39 | }); 40 | 41 | gulp.task('deleteCss', () => { 42 | return del('public/index.css'); 43 | }); 44 | 45 | gulp.task('html', gulp.series( 46 | 'pug', 47 | 'generateCss', 48 | 'inlineCss', 49 | 'deleteCss' 50 | ) 51 | ); 52 | 53 | gulp.task('js', () => { 54 | return gulp.src('src/js/*.js') 55 | .pipe(concat('index.js')) 56 | .pipe(babel({ 57 | comments: false, 58 | presets: ['env'], 59 | minified: true 60 | })) 61 | .pipe(gulp.dest('public/')); 62 | }); 63 | 64 | gulp.task('watch', () => { 65 | gulp.watch('src/**/*', gulp.parallel('js', 'html')); 66 | }); 67 | 68 | gulp.task('build', gulp.parallel('js', 'html')); 69 | 70 | gulp.task('default', gulp.series('build', 'watch')); 71 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "made-with-love-in", 3 | "version": 2, 4 | "alias": "madewithlove.now.sh", 5 | "github": { 6 | "enabled": true, 7 | "silent": true 8 | }, 9 | "builds": [{ 10 | "src": "app.js", 11 | "use": "@now/node-server", 12 | "config": { 13 | "maxLambdaSize": "45mb" 14 | } 15 | }, { 16 | "src": "/public/**/*", 17 | "use": "@now/static" 18 | } 19 | ], 20 | "routes": [ 21 | { 22 | "src": "/", 23 | "dest": "/public/index.html" 24 | }, 25 | { 26 | "src": "/index.js", 27 | "dest": "/public/index.js" 28 | }, 29 | { 30 | "src": "/icons/*", 31 | "dest": "/public/icons/$1" 32 | }, 33 | { 34 | "src": "/(.*)", 35 | "dest": "app.js" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "made-with-love-in", 3 | "version": "1.0.0", 4 | "description": "Mircoservice for serving and listing \"Made with love in \" badges", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "node app.js", 8 | "lint": "eclint check && xo", 9 | "lint:fix": "eclint fix && xo --fix" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/plibither8/made-with-love-in.git" 14 | }, 15 | "author": "Mihir Chaturvedi", 16 | "bugs": { 17 | "url": "https://github.com/plibither8/made-with-love-in/issues" 18 | }, 19 | "homepage": "https://github.com/plibither8/made-with-love-in#readme", 20 | "dependencies": { 21 | "fastify": "^3.10.1", 22 | "fastify-static": "^3.4.0", 23 | "gh-badges": "^2.1.0", 24 | "pug": "^3.0.0" 25 | }, 26 | "devDependencies": { 27 | "autoprefixer": "^10.2.3", 28 | "babel-core": "^6.26.3", 29 | "babel-preset-env": "^1.7.0", 30 | "babel-preset-latest": "^6.24.1", 31 | "cssnano": "^4.1.10", 32 | "del": "^6.0.0", 33 | "eclint": "^2.8.1", 34 | "gulp": "^4.0.2", 35 | "gulp-babel": "^8.0.0", 36 | "gulp-cli": "^2.3.0", 37 | "gulp-concat": "^2.6.1", 38 | "gulp-cssbeautify": "3.0.0", 39 | "gulp-csslint": "^1.0.1", 40 | "gulp-esformatter": "^7.0.0", 41 | "gulp-html": "3.2.0", 42 | "gulp-inline-source": "^4.0.0", 43 | "gulp-postcss": "^9.0.0", 44 | "gulp-pug": "^4.0.1", 45 | "gulp-stylus": "^2.7.0", 46 | "gulp-watch": "^5.0.1", 47 | "rucksack-css": "^1.0.2", 48 | "xo": "^0.37.1" 49 | }, 50 | "husky": { 51 | "hooks": { 52 | "pre-commit": "lint-staged" 53 | } 54 | }, 55 | "lint-staged": { 56 | "relative": true, 57 | "linters": { 58 | "src/**": [ 59 | "eclint fix", 60 | "git add" 61 | ], 62 | "src/**.{js,json}": [ 63 | "xo --fix", 64 | "git add" 65 | ] 66 | } 67 | }, 68 | "xo": { 69 | "ignore": [ 70 | "public/**/*" 71 | ], 72 | "overrides": [ 73 | { 74 | "files": "src/js/*.js", 75 | "env": [ 76 | "browser" 77 | ] 78 | } 79 | ], 80 | "global": [ 81 | "ClipboardJS", 82 | "countryNames" 83 | ] 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plibither8/made-with-love-in/6d8c264dbdd827d64df818405f9cd57901cd45a4/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/icons/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plibither8/made-with-love-in/6d8c264dbdd827d64df818405f9cd57901cd45a4/public/icons/android-chrome-256x256.png -------------------------------------------------------------------------------- /public/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plibither8/made-with-love-in/6d8c264dbdd827d64df818405f9cd57901cd45a4/public/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /public/icons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #b91d47 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plibither8/made-with-love-in/6d8c264dbdd827d64df818405f9cd57901cd45a4/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plibither8/made-with-love-in/6d8c264dbdd827d64df818405f9cd57901cd45a4/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /public/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plibither8/made-with-love-in/6d8c264dbdd827d64df818405f9cd57901cd45a4/public/icons/favicon.ico -------------------------------------------------------------------------------- /public/icons/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plibither8/made-with-love-in/6d8c264dbdd827d64df818405f9cd57901cd45a4/public/icons/heart.png -------------------------------------------------------------------------------- /public/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plibither8/made-with-love-in/6d8c264dbdd827d64df818405f9cd57901cd45a4/public/icons/mstile-150x150.png -------------------------------------------------------------------------------- /public/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/icons/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/icons/android-chrome-256x256.png", 12 | "sizes": "256x256", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | Made with ❤ in Badge

Made with ❤ inIndia

A microservice that provides a quick and easy way to add theMade with love in country-namebadge to show off your project's country of origin!

Badge Generator

Options

Your Badge

SVG

Generated badge

URL

COPY

HTML

COPY

Markdown

COPY

reStructuredText

COPY
-------------------------------------------------------------------------------- /public/index.js: -------------------------------------------------------------------------------- 1 | 'use strict';var copyButtons=document.querySelectorAll('.copy-btn');var clipboard=new ClipboardJS(copyButtons);var countryNameSpan=document.querySelector('#badge-text-B');var countrySwitchNames=function countrySwitchNames(){var nameList=Object.keys(countryNames);var index=Math.floor(Math.random()*nameList.length);var name=nameList[index];countryNameSpan.innerHTML=name};setInterval(countrySwitchNames,1500);var form=document.querySelector('form');var inputCountrySelect=document.querySelector('#input-country-select');var getSearchParamsData=function getSearchParamsData(){var formValues=Object.values(form).reduce(function(obj,field){obj[field.name]={value:field.type==='checkbox'?field.checked:field.value,default:field.dataset.default};return obj},{});var searchParamsData={};Object.keys(formValues).forEach(function(key){if(key==='country'){return}var field=formValues[key];if(field.value.toString()===field.default){return}searchParamsData[key]=field.value});return searchParamsData};var generateOutput=function generateOutput(){var countryName=inputCountrySelect.value;var searchParamsData=getSearchParamsData();var searchParams=new URLSearchParams(searchParamsData).toString();searchParams=searchParams===''?'':'?'+searchParams;var badgeUrl='https://madewithlove.now.sh/'+countryNames[countryName]+searchParams;var textB='text'in searchParamsData?searchParamsData.text:countryName;var altText='Made with love in '+textB;document.querySelector('#output-svg').src=badgeUrl;document.querySelector('#output-url').innerHTML=badgeUrl;document.querySelector('#output-html').innerHTML='<img src="'+badgeUrl+'" alt="'+altText+'">';document.querySelector('#output-md').innerHTML='!['+altText+']('+badgeUrl+')';document.querySelector('#output-rst').innerHTML='.. image:: '+badgeUrl};form.addEventListener('change',generateOutput);form.addEventListener('submit',function(e){e.preventDefault()});generateOutput(); -------------------------------------------------------------------------------- /src/js/copy-to-clipboard.js: -------------------------------------------------------------------------------- 1 | const copyButtons = document.querySelectorAll('.copy-btn'); 2 | 3 | /* eslint-disable no-unused-vars */ 4 | const clipboard = new ClipboardJS(copyButtons); 5 | /* eslint-enable no-unused-vars */ 6 | -------------------------------------------------------------------------------- /src/js/country-names-switcher.js: -------------------------------------------------------------------------------- 1 | const countryNameSpan = document.querySelector('#badge-text-B'); 2 | 3 | const countrySwitchNames = () => { 4 | const nameList = Object.keys(countryNames); 5 | const index = Math.floor(Math.random() * nameList.length); 6 | const name = nameList[index]; 7 | countryNameSpan.innerHTML = name; 8 | }; 9 | 10 | setInterval(countrySwitchNames, 1500); 11 | -------------------------------------------------------------------------------- /src/js/generate-output.js: -------------------------------------------------------------------------------- 1 | const form = document.querySelector('form'); 2 | const inputCountrySelect = document.querySelector('#input-country-select'); 3 | 4 | const getSearchParamsData = () => { 5 | const formValues = Object.values(form).reduce((obj, field) => { 6 | obj[field.name] = { 7 | value: field.type === 'checkbox' ? field.checked : field.value, 8 | default: field.dataset.default 9 | }; 10 | return obj; 11 | }, {}); 12 | 13 | const searchParamsData = {}; 14 | Object.keys(formValues).forEach(key => { 15 | if (key === 'country') { 16 | return; 17 | } 18 | 19 | const field = formValues[key]; 20 | if (field.value.toString() === field.default) { 21 | return; 22 | } 23 | 24 | searchParamsData[key] = field.value; 25 | }); 26 | 27 | return searchParamsData; 28 | }; 29 | 30 | const generateOutput = () => { 31 | const countryName = inputCountrySelect.value; 32 | 33 | const searchParamsData = getSearchParamsData(); 34 | let searchParams = new URLSearchParams(searchParamsData).toString(); 35 | searchParams = searchParams === '' ? '' : `?${searchParams}`; 36 | const badgeUrl = `https://madewithlove.now.sh/${countryNames[countryName]}${searchParams}`; 37 | 38 | const textB = 'text' in searchParamsData ? searchParamsData.text : countryName; 39 | const altText = `Made with love in ${textB}`; 40 | document.querySelector('#output-svg').src = badgeUrl; 41 | document.querySelector('#output-url').innerHTML = badgeUrl; 42 | document.querySelector('#output-html').innerHTML = `<img src="${badgeUrl}" alt="${altText}">`; 43 | document.querySelector('#output-md').innerHTML = `![${altText}](${badgeUrl})`; 44 | document.querySelector('#output-rst').innerHTML = `.. image:: ${badgeUrl}`; 45 | }; 46 | 47 | form.addEventListener('change', generateOutput); 48 | 49 | form.addEventListener('submit', e => { 50 | e.preventDefault(); 51 | }); 52 | 53 | generateOutput(); 54 | -------------------------------------------------------------------------------- /src/pug/badge-generator.pug: -------------------------------------------------------------------------------- 1 | .badge-generator 2 | 3 | h2 Badge Generator 4 | 5 | form 6 | 7 | .flex.country-selection 8 | label(for="input-country-select") Country 9 | select#input-country-select(name="country" data-default="") 10 | each key in Object.keys(countryNames).sort() 11 | option(value=key)= key 12 | 13 | h4 Options 14 | 15 | .option.flex 16 | label(for="input-heart") Use Heart (❤) 17 | input#input-heart(type="checkbox" name="heart" data-default="false") 18 | 19 | .option.flex 20 | label(for="input-colorA") Color A 21 | input#input-colorA(type="color" name="colorA" data-default="#555555" value="#555555") 22 | 23 | .option.flex 24 | label(for="input-colorB") Color B 25 | input#input-colorB(type="color" name="colorB" data-default="#dc3545" value="#dc3545") 26 | 27 | .option.flex 28 | label( for="input-template") Template 29 | select#input-template(name="template" value="flat" data-default="flat") 30 | each template in ["flat", "flat-square", "for-the-badge", "plastic", "social"] 31 | option(value=template)= template.split('-').join(' ') 32 | 33 | .option.flex 34 | label(for="input-text") Custom text 35 | input#input-text(type="text" name="text" placeholder="Custom text" data-default="") 36 | 37 | h3 Your Badge 38 | 39 | h4 SVG 40 | 41 | .svg 42 | img#output-svg(alt="Generated badge") 43 | 44 | .output.flex 45 | h4 URL 46 | .copy-btn(data-clipboard-target="#output-url") COPY 47 | 48 | .code 49 | pre#output-url 50 | 51 | .output.flex 52 | h4 HTML 53 | .copy-btn(data-clipboard-target="#output-html") COPY 54 | 55 | .code 56 | pre#output-html 57 | 58 | .output.flex 59 | h4 Markdown 60 | .copy-btn(data-clipboard-target="#output-md") COPY 61 | 62 | .code 63 | pre#output-md 64 | 65 | .output.flex 66 | h4 reStructuredText 67 | .copy-btn(data-clipboard-target="#output-rst") COPY 68 | 69 | .code 70 | pre#output-rst 71 | -------------------------------------------------------------------------------- /src/pug/head.pug: -------------------------------------------------------------------------------- 1 | title Made with ❤ in Badge 2 | 3 | base(href="/") 4 | 5 | meta(charset="utf-8") 6 | meta(lang="en") 7 | meta(name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0") 8 | meta(name="author" content="Mihir Chaturvedi (plibither8)") 9 | meta(http-equiv="X-UA-Compatible" content="IE=edge") 10 | 11 | //- Search Engine 12 | meta(name="description" content='Mircoservice for serving and listing "Made with love in " badges') 13 | meta(name='image' content='https://madewithlove.now.sh/icons/heart.png') 14 | 15 | //- Schema.org for Google 16 | meta(itemprop='name' content='Made with ❤ in ') 17 | meta(itemprop='description' content="Mircoservice for serving and listing 'Made with love in' badges") 18 | meta(itemprop='image' content='https://madewithlove.now.sh/icons/heart.png') 19 | 20 | //- Twitter 21 | meta(name='twitter:card' content='summary') 22 | meta(name='twitter:title' content='Made with ❤ in ') 23 | meta(name='twitter:description' content="Mircoservice for serving and listing 'Made with love in' badges") 24 | meta(name='twitter:site' content='@plibither8') 25 | meta(name='twitter:creator' content='@plibither8') 26 | meta(name='twitter:image:src' content='https://madewithlove.now.sh/icons/heart.png') 27 | 28 | //- Open Graph general (Facebook, Pinterest & Google+) 29 | meta(name='og:title' content='Made with ❤ in ') 30 | meta(name='og:description' content="Mircoservice for serving and listing 'Made with love in' badges") 31 | meta(name='og:url' content='https://madewithlove.now.sh') 32 | meta(name='og:site_name' content='Made with ❤ in ') 33 | meta(name='og:locale' content='en') 34 | meta(name='og:type' content='website') 35 | 36 | //- Global site tag (gtag.js) - Google Analytics 37 | script(async='', src='https://www.googletagmanager.com/gtag/js?id=UA-86157079-9') 38 | script. 39 | function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","UA-86157079-9"); 40 | 41 | //- Favicons and styles 42 | meta(name="msapplication-TileColor" content="#dc3545") 43 | meta(name="msapplication-config" content="/icons/browserconfig.xml") 44 | meta(name="theme-color" content="#dc3545") 45 | link(rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png") 46 | link(rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png") 47 | link(rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png") 48 | link(rel="manifest" href="/icons/site.webmanifest") 49 | link(rel="mask-icon" href="/icons/safari-pinned-tab.svg" color="#5bbad5") 50 | link(rel="shortcut icon" href="/icons/favicon.ico") 51 | link(rel="stylesheet" href="./index.css" inline) 52 | -------------------------------------------------------------------------------- /src/pug/index.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | 3 | html(lang="en") 4 | 5 | head 6 | include ./head.pug 7 | 8 | body 9 | 10 | .container 11 | 12 | .title-badge 13 | h1 14 | span#badge-text-A Made with ❤ in 15 | span#badge-text-B India 16 | 17 | p.intro 18 | | A microservice that provides a quick and easy way to add the 19 | img(src="https://madewithlove.now.sh/in?text=country-name" alt="Made with love in country-name") 20 | | badge to show off your project's country of origin! 21 | 22 | include ./badge-generator.pug 23 | 24 | .footer 25 | p Built overnight by Mihir Chaturvedi (plibither8). Badges have been generated by Shields.io. 26 | p View, fork, star this project and report bugs on GitHub. 27 | p Inspired by https://madewithlove.org.in. 28 | p And of course, Made with ❤ in India 29 | 30 | script. 31 | var countryNames = !{JSON.stringify(countryNames).replace(/<\//g, '<\\/')}; 32 | script(src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js") 33 | script(src="/index.js") 34 | script(src="//a.mihir.ch/s") 35 | -------------------------------------------------------------------------------- /src/styl/badge-generator.styl: -------------------------------------------------------------------------------- 1 | .badge-generator 2 | border-radius 7px 3 | padding 20px 4 | border 2px solid #e6e6e6 5 | 6 | h2 7 | font-size 24px 8 | color #222 9 | margin-bottom 20px 10 | 11 | h3 12 | margin 20px 0 13 | font-size 22px 14 | color #222 15 | 16 | h4 17 | margin 10px 0 18 | font-size 19px 19 | color #333 20 | 21 | .country-selection 22 | justify-content flex-start 23 | 24 | label 25 | margin 10px 10px 10px 0 26 | font-size 19px 27 | color #333 28 | font-weight bold 29 | 30 | .option 31 | justify-content flex-start 32 | margin 5px 0 33 | 34 | label 35 | width 150px 36 | 37 | select 38 | text-transform capitalize 39 | 40 | .svg 41 | width 100% 42 | overflow-x auto 43 | 44 | img 45 | vertical-align top 46 | 47 | .output 48 | justify-content flex-start 49 | 50 | .copy-btn 51 | cursor pointer 52 | margin-left 10px 53 | padding 5px 54 | border-radius 5px 55 | font-size 12px 56 | color #888 57 | border 2px solid #aaa 58 | font-weight bold 59 | letter-spacing 1px 60 | 61 | &:hover 62 | color #666 63 | border-color #888 64 | 65 | .code 66 | background #e6e6e6 67 | width 100% 68 | border-radius 4px 69 | overflow-x auto 70 | 71 | pre 72 | padding 10px 73 | font-size 16px 74 | display inline-block 75 | -------------------------------------------------------------------------------- /src/styl/base.styl: -------------------------------------------------------------------------------- 1 | @charset "utf-8" 2 | 3 | html, body, :root 4 | width 100% 5 | height 100% 6 | background #fff 7 | font-family system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif 8 | font-size 16px 9 | -webkit-font-smoothing antialiased 10 | -moz-osx-font-smoothing grayscale 11 | -webkit-overflow-scrolling touch 12 | 13 | @import "universal" 14 | -------------------------------------------------------------------------------- /src/styl/index.styl: -------------------------------------------------------------------------------- 1 | @require "base" 2 | 3 | .container 4 | width 95% 5 | max-width 700px 6 | margin 0 auto 7 | overflow-x hidden 8 | padding 20px 0 9 | 10 | .title-badge 11 | overflow-x auto 12 | padding 20px 0 13 | 14 | h1 15 | color #fff 16 | font-weight normal 17 | font-size 30px 18 | box-shadow 0 0 20px #bbb 19 | display inline-block 20 | white-space nowrap 21 | 22 | span 23 | padding 5px 10px 24 | &#badge-text-A 25 | background #555 26 | border-radius 7px 0 0 7px 27 | &#badge-text-B 28 | background #dc3545 29 | border-radius 0 7px 7px 0 30 | 31 | @media only screen and (max-width 800px) 32 | font-size 20px 33 | 34 | img 35 | vertical-align middle 36 | 37 | p.intro 38 | line-height 1.5 39 | color #222 40 | font-size 18px 41 | margin 10px 0 20px 0 42 | 43 | img 44 | margin 0 5px 45 | 46 | .footer 47 | margin 20px 0 48 | 49 | p 50 | font-size 16px 51 | color #444 52 | line-height 1.5 53 | text-align center 54 | padding 5px 0 55 | 56 | a 57 | color #333 58 | text-decoration underline 59 | 60 | @import "badge-generator.styl" 61 | -------------------------------------------------------------------------------- /src/styl/universal.styl: -------------------------------------------------------------------------------- 1 | * 2 | padding 0 3 | margin 0 4 | position relative 5 | box-sizing border-box 6 | text-rendering optimizeLegibility 7 | 8 | *.flex 9 | display flex 10 | align-items center 11 | justify-content center 12 | 13 | *.noselect 14 | user-select none 15 | 16 | *.nodisplay 17 | display none 18 | 19 | *.nodrag 20 | user-drag none 21 | -webkit-user-drag none 22 | user-select none 23 | 24 | a 25 | text-decoration none 26 | color inherit 27 | 28 | &:visited 29 | color inherit 30 | -------------------------------------------------------------------------------- /static/pt.svg: -------------------------------------------------------------------------------- 1 | Made with love inMade with love inPortugalPortugal --------------------------------------------------------------------------------