diff --git a/__snapshots__/make-badge.spec.js b/__snapshots__/make-badge.spec.js index c1c2ac24041036b5576e7e1b5fc83777c8b412d8..ebe7fecfcc33c2a0a60134e0ec4a79ebdafc1b93 100644 --- a/__snapshots__/make-badge.spec.js +++ b/__snapshots__/make-badge.spec.js @@ -8,3 +8,35 @@ exports['The badge generator JSON should always produce the same JSON (unless we "value": "grown" } ` + +exports['shields GitHub logo default color (#333333) 1'] = ` +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#007ec6" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMTIgMTIgNDAgNDAiPg0KPHBhdGggZmlsbD0iIzMzMzMzMyIgZD0iTTMyLDEzLjRjLTEwLjUsMC0xOSw4LjUtMTksMTljMCw4LjQsNS41LDE1LjUsMTMsMThjMSwwLjIsMS4zLTAuNCwxLjMtMC45YzAtMC41LDAtMS43LDAtMy4yIGMtNS4zLDEuMS02LjQtMi42LTYuNC0yLjZDMjAsNDEuNiwxOC44LDQxLDE4LjgsNDFjLTEuNy0xLjIsMC4xLTEuMSwwLjEtMS4xYzEuOSwwLjEsMi45LDIsMi45LDJjMS43LDIuOSw0LjUsMi4xLDUuNSwxLjYgYzAuMi0xLjIsMC43LTIuMSwxLjItMi42Yy00LjItMC41LTguNy0yLjEtOC43LTkuNGMwLTIuMSwwLjctMy43LDItNS4xYy0wLjItMC41LTAuOC0yLjQsMC4yLTVjMCwwLDEuNi0wLjUsNS4yLDIgYzEuNS0wLjQsMy4xLTAuNyw0LjgtMC43YzEuNiwwLDMuMywwLjIsNC43LDAuN2MzLjYtMi40LDUuMi0yLDUuMi0yYzEsMi42LDAuNCw0LjYsMC4yLDVjMS4yLDEuMywyLDMsMiw1LjFjMCw3LjMtNC41LDguOS04LjcsOS40IGMwLjcsMC42LDEuMywxLjcsMS4zLDMuNWMwLDIuNiwwLDQuNiwwLDUuMmMwLDAuNSwwLjQsMS4xLDEuMywwLjljNy41LTIuNiwxMy05LjcsMTMtMTguMUM1MSwyMS45LDQyLjUsMTMuNCwzMiwxMy40eiIvPg0KPC9zdmc+DQo="/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg> +` + +exports['shields GitHub logo custom color (whitesmoke) 1'] = ` +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#007ec6" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMTIgMTIgNDAgNDAiPg0KPHBhdGggZmlsbD0id2hpdGVzbW9rZSIgZD0iTTMyLDEzLjRjLTEwLjUsMC0xOSw4LjUtMTksMTljMCw4LjQsNS41LDE1LjUsMTMsMThjMSwwLjIsMS4zLTAuNCwxLjMtMC45YzAtMC41LDAtMS43LDAtMy4yIGMtNS4zLDEuMS02LjQtMi42LTYuNC0yLjZDMjAsNDEuNiwxOC44LDQxLDE4LjgsNDFjLTEuNy0xLjIsMC4xLTEuMSwwLjEtMS4xYzEuOSwwLjEsMi45LDIsMi45LDJjMS43LDIuOSw0LjUsMi4xLDUuNSwxLjYgYzAuMi0xLjIsMC43LTIuMSwxLjItMi42Yy00LjItMC41LTguNy0yLjEtOC43LTkuNGMwLTIuMSwwLjctMy43LDItNS4xYy0wLjItMC41LTAuOC0yLjQsMC4yLTVjMCwwLDEuNi0wLjUsNS4yLDIgYzEuNS0wLjQsMy4xLTAuNyw0LjgtMC43YzEuNiwwLDMuMywwLjIsNC43LDAuN2MzLjYtMi40LDUuMi0yLDUuMi0yYzEsMi42LDAuNCw0LjYsMC4yLDVjMS4yLDEuMywyLDMsMiw1LjFjMCw3LjMtNC41LDguOS04LjcsOS40IGMwLjcsMC42LDEuMywxLjcsMS4zLDMuNWMwLDIuNiwwLDQuNiwwLDUuMmMwLDAuNSwwLjQsMS4xLDEuMywwLjljNy41LTIuNiwxMy05LjcsMTMtMTguMUM1MSwyMS45LDQyLjUsMTMuNCwzMiwxMy40eiIvPg0KPC9zdmc+DQo="/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg> +` + +exports['simple-icons javascript logo default color (#F7DF1E) 1'] = ` +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#007ec6" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjRjdERjFFIiBhcmlhLWxhYmVsbGVkYnk9InNpbXBsZWljb25zLWphdmFzY3JpcHQtaWNvbiIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRpdGxlIGlkPSJzaW1wbGVpY29ucy1qYXZhc2NyaXB0LWljb24iPkphdmFTY3JpcHQgaWNvbjwvdGl0bGU+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6bTIyLjAzNCAxOC4yNzZjLS4xNzUtMS4wOTUtLjg4OC0yLjAxNS0zLjAwMy0yLjg3My0uNzM2LS4zNDUtMS41NTQtLjU4NS0xLjc5Ny0xLjE0LS4wOTEtLjMzLS4xMDUtLjUxLS4wNDYtLjcwNS4xNS0uNjQ2LjkxNS0uODQgMS41MTUtLjY2LjM5LjEyLjc1LjQyLjk3Ni45IDEuMDM0LS42NzYgMS4wMzQtLjY3NiAxLjc1NS0xLjEyNS0uMjctLjQyLS40MDQtLjYwMS0uNTg2LS43OC0uNjMtLjcwNS0xLjQ2OS0xLjA2NS0yLjgzNC0xLjAzNGwtLjcwNS4wODljLS42NzYuMTY1LTEuMzIuNTI1LTEuNzEgMS4wMDUtMS4xNCAxLjI5MS0uODExIDMuNTQxLjU2OSA0LjQ3MSAxLjM2NSAxLjAyIDMuMzYxIDEuMjQ0IDMuNjE2IDIuMjA1LjI0IDEuMTctLjg3IDEuNTQ1LTEuOTY2IDEuNDEtLjgxMS0uMTgtMS4yNi0uNTg2LTEuNzU1LTEuMzM2bC0xLjgzIDEuMDUxYy4yMS40OC40NS42ODkuODEgMS4xMDkgMS43NCAxLjc1NiA2LjA5IDEuNjY2IDYuODcxLTEuMDA0LjAyOS0uMDkuMjQtLjcwNS4wNzQtMS42NWwuMDQ2LjA2N3ptLTguOTgzLTcuMjQ1aC0yLjI0OGMwIDEuOTM4LS4wMDkgMy44NjQtLjAwOSA1LjgwNSAwIDEuMjMyLjA2MyAyLjM2My0uMTM4IDIuNzExLS4zMy42ODktMS4xOC42MDEtMS41NjYuNDgtLjM5Ni0uMTk2LS41OTctLjQ2Ni0uODMtLjg1NS0uMDYzLS4xMDUtLjExLS4xOTYtLjEyNy0uMTk2bC0xLjgyNSAxLjEyNWMuMzA1LjYzLjc1IDEuMTcyIDEuMzI0IDEuNTE3Ljg1NS41MSAyLjAwNC42NzUgMy4yMDcuNDA1Ljc4My0uMjI2IDEuNDU4LS42OTEgMS44MTEtMS40MTEuNTEtLjkzLjQwMi0yLjA3LjM5Ny0zLjM0Ni4wMTItMi4wNTQgMC00LjEwOSAwLTYuMTc5bC4wMDQtLjA1NnoiLz48L3N2Zz4="/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg> +` + +exports['simple-icons javascript logo custom color (rgba(46,204,113,0.8)) 1'] = ` +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#007ec6" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJyZ2JhKDQ2LDIwNCwxMTMsMC44KSIgYXJpYS1sYWJlbGxlZGJ5PSJzaW1wbGVpY29ucy1qYXZhc2NyaXB0LWljb24iIHJvbGU9ImltZyIgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZSBpZD0ic2ltcGxlaWNvbnMtamF2YXNjcmlwdC1pY29uIj5KYXZhU2NyaXB0IGljb248L3RpdGxlPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYwem0yMi4wMzQgMTguMjc2Yy0uMTc1LTEuMDk1LS44ODgtMi4wMTUtMy4wMDMtMi44NzMtLjczNi0uMzQ1LTEuNTU0LS41ODUtMS43OTctMS4xNC0uMDkxLS4zMy0uMTA1LS41MS0uMDQ2LS43MDUuMTUtLjY0Ni45MTUtLjg0IDEuNTE1LS42Ni4zOS4xMi43NS40Mi45NzYuOSAxLjAzNC0uNjc2IDEuMDM0LS42NzYgMS43NTUtMS4xMjUtLjI3LS40Mi0uNDA0LS42MDEtLjU4Ni0uNzgtLjYzLS43MDUtMS40NjktMS4wNjUtMi44MzQtMS4wMzRsLS43MDUuMDg5Yy0uNjc2LjE2NS0xLjMyLjUyNS0xLjcxIDEuMDA1LTEuMTQgMS4yOTEtLjgxMSAzLjU0MS41NjkgNC40NzEgMS4zNjUgMS4wMiAzLjM2MSAxLjI0NCAzLjYxNiAyLjIwNS4yNCAxLjE3LS44NyAxLjU0NS0xLjk2NiAxLjQxLS44MTEtLjE4LTEuMjYtLjU4Ni0xLjc1NS0xLjMzNmwtMS44MyAxLjA1MWMuMjEuNDguNDUuNjg5LjgxIDEuMTA5IDEuNzQgMS43NTYgNi4wOSAxLjY2NiA2Ljg3MS0xLjAwNC4wMjktLjA5LjI0LS43MDUuMDc0LTEuNjVsLjA0Ni4wNjd6bS04Ljk4My03LjI0NWgtMi4yNDhjMCAxLjkzOC0uMDA5IDMuODY0LS4wMDkgNS44MDUgMCAxLjIzMi4wNjMgMi4zNjMtLjEzOCAyLjcxMS0uMzMuNjg5LTEuMTguNjAxLTEuNTY2LjQ4LS4zOTYtLjE5Ni0uNTk3LS40NjYtLjgzLS44NTUtLjA2My0uMTA1LS4xMS0uMTk2LS4xMjctLjE5NmwtMS44MjUgMS4xMjVjLjMwNS42My43NSAxLjE3MiAxLjMyNCAxLjUxNy44NTUuNTEgMi4wMDQuNjc1IDMuMjA3LjQwNS43ODMtLjIyNiAxLjQ1OC0uNjkxIDEuODExLTEuNDExLjUxLS45My40MDItMi4wNy4zOTctMy4zNDYuMDEyLTIuMDU0IDAtNC4xMDkgMC02LjE3OWwuMDA0LS4wNTZ6Ii8+PC9zdmc+"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg> +` + +exports['The badge generator badges with logos should always produce the same badge shields GitHub logo default color (#333333) 1'] = ` +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="github"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg> +` + +exports['The badge generator badges with logos should always produce the same badge shields GitHub logo custom color (whitesmoke) 1'] = ` +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="github"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg> +` + +exports['The badge generator badges with logos should always produce the same badge simple-icons javascript logo default color (#F7DF1E) 1'] = ` +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="javascript"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg> +` + +exports['The badge generator badges with logos should always produce the same badge simple-icons javascript logo custom color (rgba(46,204,113,0.8)) 1'] = ` +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="113" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="113" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h54v20H0z"/><path fill="#4c1" d="M54 0h59v20H54z"/><path fill="url(#b)" d="M0 0h113v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="javascript"/> <text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="270">label</text><text x="365" y="140" transform="scale(.1)" textLength="270">label</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">message</text><text x="825" y="140" transform="scale(.1)" textLength="490">message</text></g> </svg> +` diff --git a/frontend/components/usage.js b/frontend/components/usage.js index 448fad5755691d7199a76c584884a3e9c89a7aca..2f615b16c4ddce3337005ec272152b024111c84d 100644 --- a/frontend/components/usage.js +++ b/frontend/components/usage.js @@ -169,7 +169,7 @@ export default class Usage extends React.PureComponent { <code>?logo=appveyor</code> </td> <td> - Insert one of the named logos ({this.constructor.renderNamedLogos()}) + Insert one of the named logos from ({this.constructor.renderNamedLogos()}) or <a href="https://simpleicons.org/" target="_BLANK">simple-icons</a> </td> </tr> <tr> @@ -178,6 +178,12 @@ export default class Usage extends React.PureComponent { </td> <td>Insert custom logo image (≥ 14px high)</td> </tr> + <tr> + <td> + <code>?logoColor=violet</code> + </td> + <td>Set the color of the logo (hex, rgb, rgba, hsl, hsla and css named colors supported)</td> + </tr> <tr> <td> <code>?logoWidth=40</code> diff --git a/lib/badge-data.js b/lib/badge-data.js index 8c72bbb393244d4a6866a80ebb6c2105e8aa7a73..8ac9f7db97b8dba21808edfb78f45fd970c5bf61 100644 --- a/lib/badge-data.js +++ b/lib/badge-data.js @@ -2,6 +2,11 @@ const isCSSColor = require('is-css-color'); const logos = require('./load-logos')(); +const simpleIcons = require('./load-simple-icons')(); +const { + svg2base64, + isDataUri, +} = require('./logo-helper'); const colorschemes = require('./colorscheme.json'); function toArray(val) { @@ -14,10 +19,6 @@ function toArray(val) { } } -function isDataUri(s) { - return s !== undefined && /^(data:)([^;]+);([^,]+),(.+)$/.test(s); -} - function prependPrefix(s, prefix) { if (s === undefined) { return undefined; @@ -39,8 +40,12 @@ function isHexColor (s = ''){ function makeColor(color) { if (isHexColor(color)) { return '#' + color; - } else { + } else if (colorschemes[color] !== undefined){ + return colorschemes[color].colorB; + } else if (isCSSColor(color)){ return color; + } else { + return undefined; } } @@ -69,9 +74,27 @@ function makeLabel(defaultLabel, overrides) { return '' + (overrides.label === undefined ? defaultLabel || '' : overrides.label); } +function getShieldsIcon(icon = '', color = ''){ + icon = typeof icon === 'string' ? icon.toLowerCase() : ''; + if (!logos[icon]){ + return undefined; + } + color = makeColor(color); + return color ? logos[icon].svg.replace(/fill="(.+?)"/g, `fill="${color}"`) : logos[icon].base64; +} + +function getSimpleIcon(icon = '', color = null){ + icon = typeof icon === 'string' ? icon.toLowerCase().replace(/ /g, '-') : ''; + if (!simpleIcons[icon]){ + return undefined; + } + color = makeColor(color); + return color ? simpleIcons[icon].svg.replace('<svg', `<svg fill="${color}"`) : simpleIcons[icon].base64; +} + function makeLogo(defaultNamedLogo, overrides) { if (overrides.logo === undefined){ - return logos[defaultNamedLogo]; + return svg2base64(getShieldsIcon(defaultNamedLogo, overrides.logoColor) || getSimpleIcon(defaultNamedLogo, overrides.logoColor)); } // +'s are replaced with spaces when used in query params, this returns them to +'s, then removes remaining whitespace - #1546 @@ -80,7 +103,7 @@ function makeLogo(defaultNamedLogo, overrides) { if (isDataUri(maybeDataUri)) { return maybeDataUri; } else { - return logos[overrides.logo]; + return svg2base64(getShieldsIcon(overrides.logo, overrides.logoColor) || getSimpleIcon(overrides.logo, overrides.logoColor)); } } @@ -116,7 +139,6 @@ function makeBadgeData(defaultLabel, overrides) { module.exports = { toArray, prependPrefix, - isDataUri, isHexColor, makeLabel, makeLogo, diff --git a/lib/badge-data.spec.js b/lib/badge-data.spec.js index 6cdf3fb9c7e7449bccb671417f42d8f57fe44c9e..75fe9d885895c8b1d427381223eaeb99d0590a38 100644 --- a/lib/badge-data.spec.js +++ b/lib/badge-data.spec.js @@ -3,12 +3,12 @@ const { expect } = require('chai'); const { test, given, forCases } = require('sazerac'); const { - isDataUri, prependPrefix, isHexColor, makeLabel, makeLogo, makeBadgeData, + makeColor, setBadgeColor } = require('./badge-data'); @@ -19,14 +19,6 @@ describe('Badge data helpers', function() { given(undefined, 'data:').expect(undefined); }); - test(isDataUri, () => { - given('data:image/svg+xml;base64,PHN2ZyB4bWxu').expect(true); - forCases([ - given('data:foobar'), - given('foobar'), - ]).expect(false); - }); - test(isHexColor, () => { forCases([ given('f00bae'), @@ -80,11 +72,20 @@ describe('Badge data helpers', function() { logoPosition: 10, logoWidth: 25, links: ['https://example.com/'], - colorA: 'blue', + colorA: '#007ec6', colorB: '#f00bae', }); }); + test(makeColor, () => { + given('red').expect('#e05d44'); + given('blue').expect('#007ec6'); + given('4c1').expect('#4c1'); + given('f00f00').expect('#f00f00'); + given('papayawhip').expect('papayawhip'); + given('purple').expect('purple'); + }); + test(setBadgeColor, () => { given({}, 'red').expect({ colorscheme: 'red' }); given({}, 'f00f00').expect({ colorB: '#f00f00' }); diff --git a/lib/load-logos.js b/lib/load-logos.js index b41f7fd3a50619d0800cddfbf04fdba43f002203..e7503f5c0112e9701212a03554fbcc553f53c3be 100644 --- a/lib/load-logos.js +++ b/lib/load-logos.js @@ -2,6 +2,7 @@ const fs = require('fs'); const path = require('path'); +const { svg2base64 } = require('./logo-helper'); function loadLogos () { // Cache svg logos from disk in base64 string @@ -12,11 +13,14 @@ function loadLogos () { if (filename[0] === '.') { return; } // filename is eg, github.svg const svg = fs.readFileSync(logoDir + '/' + filename).toString(); + const base64 = svg2base64(svg); // eg, github - const name = filename.slice(0, -('.svg'.length)); - logos[name] = 'data:image/svg+xml;base64,' + - Buffer.from(svg).toString('base64'); + const name = filename.slice(0, -('.svg'.length)).toLowerCase(); + logos[name] = { + svg, + base64 + }; }); return logos; } diff --git a/lib/load-simple-icons.js b/lib/load-simple-icons.js new file mode 100644 index 0000000000000000000000000000000000000000..278f381c19e7dc7f49b1ef7d0dbeac8a29712593 --- /dev/null +++ b/lib/load-simple-icons.js @@ -0,0 +1,18 @@ +'use strict'; + +const simpleIcons = require('simple-icons'); +const { svg2base64 } = require('./logo-helper'); + +function loadSimpleIcons(){ + Object.keys(simpleIcons).forEach(function (key) { + const k = key.toLowerCase().replace(/ /g, '-'); + if (k !== key) { + simpleIcons[k] = simpleIcons[key]; + delete simpleIcons[key]; + } + simpleIcons[k].base64 = svg2base64(simpleIcons[k].svg.replace('<svg', `<svg fill="#${simpleIcons[k].hex}"`)); + }); + return (simpleIcons); +} + +module.exports = loadSimpleIcons; diff --git a/lib/logo-helper.js b/lib/logo-helper.js new file mode 100644 index 0000000000000000000000000000000000000000..93d88535c16cbe0a1f6526b73baac9666d04ef14 --- /dev/null +++ b/lib/logo-helper.js @@ -0,0 +1,18 @@ +'use strict'; + +function isDataUri(s) { + return s !== undefined && /^(data:)([^;]+);([^,]+),(.+)$/.test(s); +} + +function svg2base64(svg){ + if (typeof svg !== 'string'){ + return undefined; + } + // Check if logo is already base64 + return isDataUri(svg) ? svg : 'data:image/svg+xml;base64,' + Buffer.from(svg).toString('base64'); +} + +module.exports = { + svg2base64, + isDataUri, +} diff --git a/lib/logo-helper.spec.js b/lib/logo-helper.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..0efc4b17edc0f412688c54734167521df8eb58e3 --- /dev/null +++ b/lib/logo-helper.spec.js @@ -0,0 +1,27 @@ +'use strict'; + +const { + test, + given, + forCases, +} = require('sazerac'); +const { + svg2base64, + isDataUri, +} = require('./logo-helper'); + +describe('Logo helpers', function() { + test(svg2base64, () => { + given('data:image/svg+xml;base64,PHN2ZyB4bWxu').expect('data:image/svg+xml;base64,PHN2ZyB4bWxu'); + given('<svg xmlns="http://www.w3.org/2000/svg"/>').expect('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciLz4='); + given(undefined).expect(undefined); + }); + + test(isDataUri, () => { + given('data:image/svg+xml;base64,PHN2ZyB4bWxu').expect(true); + forCases([ + given('data:foobar'), + given('foobar'), + ]).expect(false); + }); +}); diff --git a/lib/make-badge.spec.js b/lib/make-badge.spec.js index cd733776b6d25e1d3d7a08be4a91c3cb236a13cf..898e2eebff4dd1ff956639451a8c668f05da4220 100644 --- a/lib/make-badge.spec.js +++ b/lib/make-badge.spec.js @@ -127,4 +127,25 @@ describe('The badge generator', () => { expect(svg).to.include('""').and.to.include('some-value'); }); }); + describe('badges with logos should always produce the same badge', () => { + it('shields GitHub logo default color (#333333)', () => { + const svg = makeBadge({ text: ['label', 'message'], format: 'svg', logo: 'github' }); + snapshot(svg); + }); + + it('shields GitHub logo custom color (whitesmoke)', () => { + const svg = makeBadge({ text: ['label', 'message'], format: 'svg', logo: 'github', logoColor: 'whitesmoke' }); + snapshot(svg); + }); + + it('simple-icons javascript logo default color (#F7DF1E)', () => { + const svg = makeBadge({ text: ['label', 'message'], format: 'svg', logo: 'javascript' }); + snapshot(svg); + }); + + it('simple-icons javascript logo custom color (rgba(46,204,113,0.8))', () => { + const svg = makeBadge({ text: ['label', 'message'], format: 'svg', logo: 'javascript', logoColor: 'rgba(46,204,113,0.8)' }); + snapshot(svg); + }); + }); }); diff --git a/lib/request-handler.js b/lib/request-handler.js index 998d80e5694b241de9b01302ca56993c9273a3dc..8918666f73258ecd74ae19c1102c88d6b8186d89 100644 --- a/lib/request-handler.js +++ b/lib/request-handler.js @@ -40,6 +40,7 @@ const globalQueryParams = new Set([ 'style', 'link', 'logo', + 'logoColor', 'logoPosition', 'logoWidth', 'link', diff --git a/package-lock.json b/package-lock.json index 8ae2da771c864333c2b64b6971ea7019a2379bf8..478f1159afa16f02def960b72b8002ef7d7ff0a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5369,6 +5369,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", "dev": true, + "optional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -5440,7 +5441,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "dev": true, + "optional": true }, "delegates": { "version": "1.0.0", @@ -5765,13 +5767,15 @@ "version": "1.27.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=", - "dev": true + "dev": true, + "optional": true }, "mime-types": { "version": "2.1.15", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", "dev": true, + "optional": true, "requires": { "mime-db": "~1.27.0" } @@ -5855,7 +5859,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true }, "oauth-sign": { "version": "0.8.2", @@ -13130,6 +13135,11 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "simple-icons": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-1.7.1.tgz", + "integrity": "sha1-xoVlvjKsRsq4N7IZrnGuu6T9JVM=" + }, "sinon": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.0.0.tgz", diff --git a/package.json b/package.json index 27d8a09d5f16e4311557dcf15c737a3763cb14c4..7c2054a0796395c5c7eb4292332d3a72b9ed9151 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "redis": "~2.6.2", "request": "~2.87.0", "semver": "~5.5.0", + "simple-icons": "^1.7.1", "svgo": "~1.0.5", "xml2js": "~0.4.16", "xmldom": "~0.1.27",