├── .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 | 
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 |
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 BadgeMade with ❤ inIndia
A microservice that provides a quick and easy way to add the
badge to show off your project's country of origin!
Badge Generator
Your Badge
SVG
--------------------------------------------------------------------------------
/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='';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 = ``;
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,
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 |
--------------------------------------------------------------------------------