Generate badge examples from data + code (#1163)

This pull request sets us up to generate the badge examples dynamically from data and code.

Right now, try.html is still checked in, mostly for the benefit of reading this diff, though it should be removed on the next pass to avoid unnecessary complexity at merge time.
This commit is contained in:
Paul Melnikow
2017-10-20 17:33:12 -04:00
committed by GitHub
parent 8ac0605e12
commit b411f08ad1
13 changed files with 6038 additions and 1248 deletions

3
.gitignore vendored
View File

@@ -85,3 +85,6 @@ typings/
# dotenv environment variables file
.env
# Temporary build artifacts.
/build

View File

@@ -14,6 +14,9 @@ favicon:
node gh-badge.js '' '' '#bada55' .png > favicon.png
website:
@mkdir -p build && \
node_modules/.bin/babel-node frontend/render-badge-examples && \
cat frontend/fragments/try-header.html build/badge-examples-fragment.html frontend/fragments/try-footer.html > try.html && \
cat try.html | $(SED) "s,(<img src=')(/[^'\?]+)',\1https://img.shields.io\2?maxAge=2592000'," \
| $(SED) "s,(<img src=')(/[^'\?]+\?[^']+)',\1https://img.shields.io\2\&maxAge=2592000'," \
| $(SED) "s,<span id='imgUrlPrefix'>,&https://img.shields.io," \

7
frontend/.eslintrc.yml Normal file
View File

@@ -0,0 +1,7 @@
extends:
- 'standard-jsx'
- '../.eslintrc-preferred.yml'
parserOptions:
ecmaFeatures:
jsx: true

View File

@@ -0,0 +1,45 @@
'use strict';
const React = require('react');
const Badge = (props) => {
const attrs = {};
if (props.documentation) {
attrs['data-doc'] = props.documentation;
}
if (props.keywords) {
attrs['data-keywords'] = props.keywords.join(' ');
}
const previewImage = props.previewUri
? (<img src={props.previewUri} alt="" />)
: '\u00a0'; // non-breaking space
const exampleUri = `https://img.shields.io${props.exampleUri || props.previewUri}`;
return (
<tr><th {... attrs}>{ props.title }:</th>
<td>{ previewImage }</td>
<td><code>{ exampleUri }</code></td>
</tr>
)
}
const Category = (props) => (
<div>
<h3 id={props.category.id}>{ props.category.name }</h3>
<table className='badge'><tbody>
{
props.examples.map((badgeData, i) => (<Badge key={i} {...badgeData} />))
}
</tbody></table>
</div>
)
const BadgeExamples = (props) => (
<div>
{
props.examples.map((categoryData, i) => (<Category key={i} {...categoryData} />))
}
</div>
);
module.exports = BadgeExamples;

17
frontend/convert-to-js Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
rm ../lib/all-badge-examples.js
cat >../lib/all-badge-examples.js <<HERE
'use strict';
const allBadgeExamples =
HERE
cat ../all-badges.json >> ../lib/all-badge-examples.js
sed -Ei '' -e 's/\"([a-zA-Z]+)\":/\1:/' ../lib/all-badge-examples.js
sed -Ei '' -e "s/\"/\'/g" ../lib/all-badge-examples.js
cat >>../lib/all-badge-examples.js <<HERE
module.exports = allBadgeExamples;
HERE

View File

@@ -0,0 +1,50 @@
// Generate a JSON file from try.html with the initial badge example data.
'use strict';
const fs = require('fs');
const path = require('path');
const cheerio = require('cheerio');
const inputPath = path.join(__dirname, '..', 'try.html');
const html = fs.readFileSync(inputPath);
const $ = cheerio.load(html);
const sectionHeaders = $('h3');
const sections = [];
$('table.badge').each((i, table) => {
const category = {
id: sectionHeaders.eq(i).attr('id'),
name: sectionHeaders.eq(i).text().trim(),
};
const examples = [];
$(table).find('tr').each((i, row) => {
const th = $(row).find('th');
const keywordsAttr = th.attr('data-keywords');
const previewUri = $(row).find('img').attr('src');
const exampleUri = $(row).find('code').text().replace(/^https:\/\/img\.shields\.io/, '');
const rowData = {
title: th.text().trim().replace(/:$/, ''),
previewUri,
keywords: keywordsAttr ? keywordsAttr.split(' ') : undefined,
documentation: th.attr('data-doc'),
};
if (exampleUri !== previewUri) {
rowData.exampleUri = exampleUri;
}
examples.push(rowData);
})
sections.push({ category, examples });
})
const outputPath = path.join(__dirname, '..', 'all-badges.json');
fs.writeFileSync(outputPath, JSON.stringify(sections, 0, 2));

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,491 @@
<h2 id="your-badge"> Your Badge </h2>
<form action='javascript:makeImage()' id='imageMaker'>
<input class='short' name='subject' placeholder='subject'/>
<input class='short' name='status' placeholder='status'/>
<input class='short' name='color' list='default-colors' placeholder='color'/>
<datalist id='default-colors'>
<option value='brightgreen'>
<option value='green'>
<option value='yellowgreen'>
<option value='yellow'>
<option value='orange'>
<option value='red'>
<option value='lightgrey'>
<option value='blue'>
</datalist>
<button>Make Badge</button>
</form>
<hr class='spacing'/>
<p>
<code><span id='imgUrlPrefix'>/badge/</span>&lt;SUBJECT&gt;-&lt;STATUS&gt;-&lt;COLOR&gt;.svg</code>
</p>
<table class=centered><tbody>
<tr><td> Dashes <code>--</code>
</td><td>
</td><td> <code>-</code> Dash
</td></tr>
<tr><td> Underscores <code>__</code>
</td><td>
</td><td> <code>_</code> Underscore <br/>
</td></tr>
<tr><td> <code>_</code> or Space <code>&nbsp;</code>
</td><td>
</td><td> <code>&nbsp;</code> Space
</td></tr>
</tbody></table>
<p class='badge-img'>
<img src='/badge/color-brightgreen-brightgreen.svg' alt='brightgreen'/>
<img src='/badge/color-green-green.svg' alt='green'/>
<img src='/badge/color-yellowgreen-yellowgreen.svg' alt='yellowgreen'/>
<img src='/badge/color-yellow-yellow.svg' alt='yellow'/>
<img src='/badge/color-orange-orange.svg' alt='orange'/>
<img src='/badge/color-red-red.svg' alt='red'/>
<img src='/badge/color-lightgrey-lightgrey.svg' alt='lightgrey'/>
<img src='/badge/color-blue-blue.svg' alt='blue'/>
<img src='/badge/color-ff69b4-ff69b4.svg' alt='ff69b4'/>
</p>
<h2 id="styles"> Styles </h2>
<p>
The following styles are available (flat is the default as of Feb 1st 2015):
</p>
<table class='badge-img'><tbody>
<tr>
<td><img src='/badge/style-plastic-green.svg?style=plastic' alt=''/></td>
<td><code>https://img.shields.io/badge/style-plastic-green.svg?style=plastic</code></td>
</tr>
<tr>
<td><img src='/badge/style-flat-green.svg?style=flat' alt=''/></td>
<td><code>https://img.shields.io/badge/style-flat-green.svg?style=flat</code></td>
</tr>
<tr>
<td><img src='/badge/style-flat--squared-green.svg?style=flat-square' alt=''/></td>
<td><code>https://img.shields.io/badge/style-flat--squared-green.svg?style=flat-square</code></td>
</tr>
<tr>
<td><img src='/badge/style-for--the--badge-green.svg?style=for-the-badge' alt=''/></td>
<td><code>https://img.shields.io/badge/style-for--the--badge-green.svg?style=for-the-badge</code></td>
</tr>
<tr>
<td><img src='/badge/style-social-green.svg?style=social' alt=''/></td>
<td><code>https://img.shields.io/badge/style-social-green.svg?style=social</code></td>
</tr>
</tbody></table>
<p>
Here are a few other parameters you can use: (connecting several with "&" is possible)
</p>
<table><tbody>
<tr><td><code>?label=healthinesses</code></td><td>Override the default
left-hand-side text (<a href="https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding">URL-Encoding</a> needed for spaces or special characters!)</td>
<tr><td><code>?logo=appveyor</code></td>
<td>
Insert one of the
<a href="https://github.com/badges/shields/tree/gh-pages/logo">named logos</a>
</td></tr>
<tr><td><code>?logo=data:image/png;base64,…</code></td>
<td>Insert custom logo image (≥ 14px high)</td></tr>
<tr><td><code>?logoWidth=40</code></td>
<td>Set the horizontal space to give to the logo</td></tr>
<tr><td><code>?link=http://left&amp;link=http://right</code></td>
<td>Specify what clicking on the left/right of a badge should do (esp. for
social badge style)</td></tr>
<tr><td><code>?colorA=abcdef</code></td>
<td>Set background of the left part (hex color only)</td></tr>
<tr><td><code>?colorB=fedcba</code></td>
<td>Set background of the right part (hex color only)</td></tr>
<tr><td><code>?maxAge=3600</code></td>
<td>Set the HTTP cache lifetime in secs</td></tr>
</tbody></table>
<p>
We support <code>.svg</code>, <code>.json</code>, <code>.png</code> and a few
others, but use them responsibly.
</p>
<h2 id="like-this"> Like This? </h2>
<p>
Tell your favorite badge service to use it! <br/>
And tell us, we might be able to bring it to you anyway!
</p>
<p>
<object data='/twitter/follow/shields_io.svg?style=social&label=Follow' alt='Follow @shields_io'></object>
<object data='/gratipay/Shields.svg?style=social&label=Donate&link=https://www.gratipay.com/Shields/' alt='Donate to us!'></object>
<object data='/github/forks/badges/shields.svg?style=social&label=Fork' alt='Fork on GitHub'></object>
<object data='/discord/308323056592486420.svg?style=social&label=Chat&link=https://discord.gg/HjJCwm5' alt='chat on Discord'></object>
</p>
<p>
<a href='https://github.com/h5bp/lazyweb-requests/issues/150'>This</a>
is where the current server got started.
</p>
<p><small>:wq</small></p>
</main>
<dialog id='copyDialog'>
<form id='copyForm' action='javascript:void 0'>
<p><img id='copyImg'>
</p><p><label> Link <input type='url' name='url'/></label>
</p><p><label> Image <input type='url' name='img'/></label>
</p><p><label> Style
<select name='style'>
<option value='plastic'> plastic
<option value='flat' selected> flat
<option value='flat-square'> flat-square
</select>
</label>
</p><p> Markdown
<input class=code id=copyMarkdown>
</p><p> reStructuredText
<input class=code id=copyreStructuredText>
</p><p> AsciiDoc
<input class=code id=copyAsciiDoc>
</p><div id=copyDoc></div>
</form>
</dialog>
<div id=documentation style='display:none'>
<div id=visualStudioTeamServices>
<p>To obtain your own badge, you will first need to enable badges for your
project:
</p>
<img
src='https://cloud.githubusercontent.com/assets/6189336/11894616/be744ab4-a578-11e5-9e44-0c32a7836b3b.png'
alt='Go to your builds, click General, then check Badge enabled.'>
<p>Then, click “Show url…” to reveal the URL of the default badge. In that
URL, you will need to extract three pieces of information:
<code>TEAM_NAME</code>, <code>PROJECT_ID</code> and
<code>BUILD_DEFINITION_ID</code>.
</p>
<img
src='https://cloud.githubusercontent.com/assets/6189336/11629345/f4eb0d78-9cf7-11e5-8d83-ca9fd895fcea.png'
alt='TEAM_NAME is just after the https:// part, PROJECT_ID is after
definitions/, BUILD_DEFINITION_ID is after that.'>
<p>Your badge will then have the form
<code>https://img.shields.io/vso/build/TEAM_NAME/PROJECT_ID/BUILD_DEFINITION_ID</code>.
</p>
</div>
<div id="websiteDoc">
<p>The badge is of the form <code>https://img.shields.io/website[OPTIONS]/PROTOCOL/URLREST.svg</code>,
the simplest case being <code>https://img.shields.io/website/http/example.com.svg</code>.
More options are described below.
</p>
<p>The whole URL is obtained by concatenating the <code>PROTOCOL</code> (<code>http</code> or <code>https</code>, for example)
with the <code>URLREST</code> (separating them with <code>://</code>).
</p>
<p>
The existence of a specific path on the server can be checked by appending a path after the domain name, e.g.
<code>https://img.shields.io/website/http/www.website.com/path/to/page.html.svg</code>.
</p>
<p>The URLREST should be URLEncoded:<br>
<input type="text" id="websiteDocUrlField" placeholder="Paste your URL (without the protocol) here" /><br>
<button onclick="(function(el) { el.value = encodeURIComponent(el.value); })(document.getElementById('websiteDocUrlField'))">Encode</button>
<button onclick="(function(el) { el.value = decodeURIComponent(el.value); })(document.getElementById('websiteDocUrlField'))">Decode</button>
</p>
<p><code>[OPTIONS]</code> can be:
<ul>
<li>Nothing:
<code>…/website/…</code></li>
<li>Online and offline text:
<code>…/website-up-down/…</code></li>
<li>Online and offline text, then online and offline colors:
<code>…/website-up-down-green-orange/…</code></li>
</ul>
<table class=centered><tbody>
<tr><td> Dashes <code>--</code>
</td><td>
</td><td> <code>-</code> Dash
</td></tr>
<tr><td> Underscores <code>__</code>
</td><td>
</td><td> <code>_</code> Underscore <br/>
</td></tr>
<tr><td> Slashes <code>//</code>
</td><td>
</td><td> <code>/</code> Slash <br/>
</td></tr>
<tr><td> <code>_</code> or Space <code>&nbsp;</code>
</td><td>
</td><td> <code>&nbsp;</code> Space
</td></tr>
</tbody></table>
</p>
</div>
<div id="githubDoc">
<p>If your GitHub badge errors, it might be because you hit GitHub's rate
limits.<br>
You can increase Shields.io's rate limit by
<a href="https://img.shields.io/github-auth">going to this page</a>
to add Shields as a GitHub application on your GitHub account.
</p>
</div>
<div id="jira-sprint-completion">
<p>To get the <code>Sprint ID</code>, go to your Backlog view in your project, right click on your sprint name and get the value of <code>data-sprint-id</code>.</p>
</div>
</div>
<svg style='height:0'>
<filter id='gaussian-blur'>
<feGaussianBlur stdDeviation='0.7' />
</filter>
</svg>
<script>
// Search
//
var searchBadgeDb = {index: [], tr: []};
function searchBadgeDbInit() {
searchBadgeDb = {index: [], tr: []};
var trs = document.querySelectorAll('table.badge tr');
for (var i = 0; i < trs.length; i++) {
var tr = trs[i];
var th = tr.firstElementChild;
var keywords = th.dataset.keywords? th.dataset.keywords: '';
searchBadgeDb.index.push(th.textContent + ' ' + keywords);
searchBadgeDb.tr.push(tr);
}
projectSearch.addEventListener('input', searchBadge);
}
function searchBadge(event) {
var query = event.target.value;
var regex = new RegExp(query, 'i'); // Case-insensitive
for (var i = 0; i < searchBadgeDb.index.length; i++) {
if (regex.test(searchBadgeDb.index[i])) {
searchBadgeDb.tr[i].removeAttribute('style');
} else {
searchBadgeDb.tr[i].style.display = 'none';
}
}
// If it has the format of a url, show the suggest button.
if (isUrl(query)) { showSuggestButton();
} else { hideSuggestButton();
}
}
document.addEventListener('DOMContentLoaded', searchBadgeDbInit);
// Suggested badges search
//
function isUrl(url) {
var http = url.slice(0, 5) === 'http:';
var https = url.slice(0, 6) === 'https:';
return http || https;
}
function showSuggestButton() { suggestButton.style.display = 'inline'; }
function hideSuggestButton() { suggestButton.style.display = 'none'; }
function showSuggestedBadges(badges) {
var html = '<table class="badge"><tbody>';
for (var i = 0; i < badges.length; i++) {
var link = badges[i].link;
var badge = badges[i].badge;
var name = badges[i].name + ':';
html += '<tr><th data-link="' + link + '">' + name + '</th>' +
'<td><img src="' + badge + '"></td>' +
'<td><code>' + badge + '</code></td>' +
'</tr>';
}
html += '</tbody></table>';
suggestedBadges.innerHTML = html;
suggestedBadges.style.display = 'block';
}
function suggestBadges(event) {
var url = event.target.projectSearch.value;
if (isUrl(url)) {
ajax('suggest/v1', {url:url}, function(err, res) {
if (err != null) { return; }
showSuggestedBadges(res.badges);
suggestButton.disabled = false;
searchBadgeDbInit();
markupDialogInit();
});
suggestButton.disabled = true;
}
}
function suggestBadgeInit() {
searchForm.addEventListener('submit', suggestBadges);
}
document.addEventListener('DOMContentLoaded', suggestBadgeInit);
// Auto-select code snippets
//
// Select and highlight the node's textual content.
// Use this as an event listener.
function selectNode(e) {
if (e.target.select) {
e.target.select();
} else {
if (document.selection) {
var range = document.body.createTextRange();
range.moveToElementText(e.target);
range.select();
} else if (window.getSelection) {
var range = document.createRange();
range.selectNode(e.target);
window.getSelection().addRange(range);
}
}
};
copyMarkdown.addEventListener('click', selectNode);
copyreStructuredText.addEventListener('click', selectNode);
copyAsciiDoc.addEventListener('click', selectNode);
// Markup copier dialog
//
function markupDialogInit() {
var trs = document.querySelectorAll('table.badge tr');
for (var i = 0; i < trs.length; i++) {
var tr = trs[i];
var title = tr.querySelector('th');
var target = tr.querySelector('img');
var code = tr.querySelector('code');
// Markup dialog listener.
var mdl = makeMarkupDialogListener(tr);
if (title != null) { title.addEventListener('click', mdl); }
if (target != null) { target.addEventListener('click', mdl); }
if (code != null) { code.addEventListener('click', mdl); }
}
}
function makeMarkupDialogListener(tr) {
return function(event) { markupDialog(tr); event.stopPropagation(); };
}
document.addEventListener('DOMContentLoaded', markupDialogInit);
var copyFormUrlEventListener;
function markupDialog(tr) {
// Set up the data we have.
// Trim the ending colon `:`.
var trname = tr.firstElementChild.textContent.trim().slice(0, -1);
var trimg = tr.querySelector('img').src;
var th = tr.firstElementChild;
var link = th.dataset.link? th.dataset.link: '';
// Remove the ?maxAge parameter from the query string.
trimg = trimg.replace(/[\?&]maxAge=\d+$|maxAge=\d+&/, '');
copyForm.img.value = trimg;
copyForm.url.value = link;
// Insert documentation.
var doc = th.dataset.doc? th.dataset.doc: '';
var docelt = document.getElementById(doc);
if (docelt != null) {
copyDoc.innerHTML = '<h4>Documentation</h4>' + docelt.innerHTML;
} else {
copyDoc.innerHTML = '';
}
// Set up the input listeners.
copyForm.url.removeEventListener('input', copyFormUrlEventListener);
copyForm.img.removeEventListener('input', copyFormUrlEventListener);
copyForm.style.removeEventListener('change', copyFormUrlEventListener);
copyFormUrlEventListener = function(event) {
var url = copyForm.url.value;
var img = copyForm.img.value;
var style = copyForm.style.value;
// Default style doesn't need value
if (style !== 'flat') {
img += (img.indexOf('?') != -1 ? '&style=' : '?style=') + style;
}
var md = '[![' + trname + '](' + img + ')](' + url + ')';
var rst = '.. image:: ' + img + ' :target: ' + url;
var adoc = 'image:' + img + '[' + trname + ']';
copyMarkdown.value = md;
copyreStructuredText.value = rst;
copyAsciiDoc.value = adoc;
copyImg.src = img;
};
copyForm.url.addEventListener('input', copyFormUrlEventListener);
copyForm.img.addEventListener('input', copyFormUrlEventListener);
copyForm.style.addEventListener('change', copyFormUrlEventListener);
// Set up the window position
var h = document.documentElement.offsetHeight;
copyDialog.style.height = h + 'px';
// Set up hide listener and show.
copyFormUrlEventListener();
markupDialogShow();
}
var isFirefox = /Firefox\/[\.0-9]+$/.test(navigator.userAgent);
function markupDialogShow() {
document.body.addEventListener('click', markupDialogHide);
// We must draw it once displayed before changing the opacity to transition.
setTimeout(function() { copyDialog.style.opacity = '1'; }, 20);
if (!isFirefox) {
main.classList.add('blur');
} else {
// We must delay blurring to avoid sloppy transition in Firefox.
setTimeout(function() { main.classList.add('blur'); }, 500);
}
copyDialog.style.display = 'block';
}
function markupDialogHide() {
document.body.removeEventListener('click', markupDialogHide);
copyDialog.style.opacity = '0';
main.classList.remove('blur');
setTimeout(function() { copyDialog.style.display = 'none'; }, 500);
}
copyForm.addEventListener('click', function(event) {
event.stopPropagation();
});
// Custom badge
//
function makeImage() {
var url = document.getElementById('imgUrlPrefix').textContent;
url += escapeField(imageMaker.subject.value);
url += '-' + escapeField(imageMaker.status.value);
url += '-' + escapeField(imageMaker.color.value);
url += '.svg';
document.location = url;
}
function escapeField(s) {
return encodeURIComponent(s.replace(/-/g, '--').replace(/_/g, '__'));
}
// Convert object literal to xhr-sendable.
//
function toXhrSend(data) {
var str = '', start = true;
var jsondata = '';
for (var key in data) {
if (typeof (jsondata = JSON.stringify(data[key])) === 'string') {
str += (start? '': '&');
if (typeof data[key] === 'string') {
str += encodeURIComponent(key) + '=' + encodeURIComponent(data[key]);
} else {
str += encodeURIComponent(key) + '=' + encodeURIComponent(jsondata);
}
start = false;
}
}
return str;
}
var origin = '';
function ajax(verb, adverbs, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", origin + "/$" + verb + '?' + toXhrSend(adverbs), true);
xhr.onload = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
cb(null, JSON.parse(xhr.responseText));
} catch(e) {cb(e);}
}
}
};
xhr.onerror = function (e) { cb(Error(xhr.statusText)); };
xhr.send(null);
}
</script>

View File

@@ -0,0 +1,71 @@
<!doctype html><meta charset=utf-8>
<title> Shields.io: Quality metadata badges for open source projects </title>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<meta name='description' content='We serve fast and scalable informational
images as badges for GitHub, Travis CI, Jenkins, WordPress and many more
services. Use them to track the state of your projects, or for promotional
purposes.'>
<link rel='icon' type='image/png' href='favicon.png'>
<link href='//fonts.googleapis.com/css?family=Lekton' rel='stylesheet'>
<style>
html { background-attachment: fixed;
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDAiIGhlaWdodD0iNDgwIj48ZmlsdGVyIGlkPSJhIj48ZmVUdXJidWxlbmNlIGJhc2VGcmVxdWVuY3k9Ii4wOCIgbnVtT2N0YXZlcz0iOCIgc3RpdGNoVGlsZXM9InN0aXRjaCIgc2VlZD0iMzQ2Ii8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIxIDAgMCAwIDAgIDEgMCAwIDAgMCAgMSAwIDAgMCAuOSAgLjAxIDAgMCAwIC4wMSIvPjwvZmlsdGVyPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNhKSIvPjwvc3ZnPg==);
}
:root, dialog { text-align: center; font-family: Lekton, sans-serif; color: #534; }
code, .code { font-family: Lekton; white-space: pre-wrap; padding: 0 4px;
background: #eef; border-radius: 4px; }
input.short { width: 5em; }
input { text-align: center; border: solid #b9a; color: #534; border-width: 0 0 1px 0;
width: 40%; height: 15px; padding: 0; background-color: transparent; }
input:focus { outline: 0; }
hr { width: 40%; border-width: 1px 0 0 0; }
a.photo { text-decoration: none; }
a.photo>img { padding: 2px; border: 1px solid grey; }
ul { text-align: left; margin-left: 25%; }
table { min-width: 50%; margin: auto; }
table.centered > tbody > tr > td:first-child { text-align: right; }
th, td { text-align: left; }
h1, h2, h3 { font-style: italic; }
h2::before { content: '☙ '; }
h2::after { content: ' ❧'; }
h2 { margin-top: 12mm; font-variant: small-caps; }
hr.spacing { border: 0; display: block; height: 3mm; }
.highlights { font-style: italic; }
#main { transition: filter 1s, -webkit-filter 1s; }
#main.blur { filter: url(#gaussian-blur); filter: blur(1px); -webkit-filter: blur(1px); }
#copyDialog { display: none; position: fixed; width: 100%; top: 0; left: 0;
border: 0; background-color: rgba(50,50,55,0.7);
opacity: 0; transition: opacity 0.5s; }
#copyForm { background: #fafaff; position: fixed; width: 100%;
top: 17%; left: 0;
overflow: auto;
max-height: 56%;
border-top: 15px solid #eaeaff;
border-bottom: 15px solid #eaeaff;
}
#suggestButton { display: none; }
table.badge > tbody > tr > th,
table.badge > tbody > tr > td > img,
table.badge > tbody > tr > td > code { cursor: pointer; }
table.badge > tbody > tr > td > img, .badge-img img, #copyImg {
height: 20px;
vertical-align: middle;
}
</style>
<main id='main'>
<img alt='Shields IO' src='logo.svg'/>
<hr class='spacing'/>
<p class=highlights>
Pixel-perfect &nbsp; Retina-ready &nbsp; Fast &nbsp; Consistent &nbsp; Hackable &nbsp; No tracking
</p>
<form id='searchForm' action='javascript:void 0' autocomplete=off>
<input name='projectSearch' id='projectSearch' autofill=off autofocus placeholder='search / project URL'/>
<br>
<button id='suggestButton'> Suggest badges </button>
</form>
<a href='https://gratipay.com/Shields/' style='text-decoration:none;color:rgba(0,0,0,0.1)'>donate</a>
<section id='suggestedBadges'></section>

View File

@@ -0,0 +1,18 @@
'use strict';
const fs = require('fs');
const path = require('path');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const pretty = require('pretty');
const BadgeExamples = require('./badge-examples');
// const inputPath = path.join(__dirname, '..', 'all-badges.json');
// const badgeExampleData = JSON.parse(fs.readFileSync(inputPath));
const badgeExampleData = require('../lib/all-badge-examples');
const fragment = ReactDOMServer.renderToStaticMarkup(
<BadgeExamples examples={badgeExampleData} />);
const outputPath = path.join(__dirname, '..', 'build', 'badge-examples-fragment.html');
fs.writeFileSync(outputPath, pretty(fragment));

1884
lib/all-badge-examples.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -51,6 +51,7 @@
"test:services:pr:run": "mocha --delay service-tests/runner/cli.js --stdin < pull-request-services.log",
"test:services:pr": "npm run test:services:pr:prepare && npm run test:services:pr:run",
"test": "npm run lint && npm run test:js",
"build": "make website",
"start": "node server 8080 ::"
},
"bin": {
@@ -68,15 +69,21 @@
"logo"
],
"devDependencies": {
"babel-cli": "^6.11.4",
"babel-core": "^6.13.2",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.11.1",
"child-process-promise": "^2.2.1",
"dejavu-fonts-ttf": "^2.37.3",
"eslint": "^4.8.0",
"eslint-config-prettier": "^2.6.0",
"eslint-config-standard": "^10.2.1",
"eslint-config-standard-jsx": "^4.0.2",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-node": "^5.2.0",
"eslint-plugin-prettier": "^2.3.1",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-react": "^7.4.0",
"eslint-plugin-standard": "^3.0.1",
"glob": "^7.1.1",
"icedfrisby": "^1.4.0",
@@ -91,6 +98,9 @@
"nyc": "^11.2.1",
"opn-cli": "^3.1.0",
"prettier": "1.7.4",
"pretty": "^2.0.0",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"read-all-stdin-sync": "^1.0.5",
"rimraf": "^2.6.2",
"semver-regex": "^1.0.0",
@@ -98,5 +108,11 @@
},
"engines": {
"node": ">= 6"
},
"babel": {
"presets": [
"react",
"env"
]
}
}

3435
try.html

File diff suppressed because it is too large Load Diff