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:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -85,3 +85,6 @@ typings/
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# Temporary build artifacts.
|
||||
/build
|
||||
|
||||
3
Makefile
3
Makefile
@@ -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
7
frontend/.eslintrc.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extends:
|
||||
- 'standard-jsx'
|
||||
- '../.eslintrc-preferred.yml'
|
||||
|
||||
parserOptions:
|
||||
ecmaFeatures:
|
||||
jsx: true
|
||||
45
frontend/badge-examples.js
Normal file
45
frontend/badge-examples.js
Normal 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
17
frontend/convert-to-js
Executable 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
|
||||
50
frontend/extract-badge-examples.js
Normal file
50
frontend/extract-badge-examples.js
Normal 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));
|
||||
1246
frontend/fragments/badge-examples-old.html
Normal file
1246
frontend/fragments/badge-examples-old.html
Normal file
File diff suppressed because it is too large
Load Diff
491
frontend/fragments/try-footer.html
Normal file
491
frontend/fragments/try-footer.html
Normal 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><SUBJECT>-<STATUS>-<COLOR>.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> </code>
|
||||
</td><td> →
|
||||
</td><td> <code> </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&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> </code>
|
||||
</td><td> →
|
||||
</td><td> <code> </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 = '[](' + 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>
|
||||
71
frontend/fragments/try-header.html
Normal file
71
frontend/fragments/try-header.html
Normal 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 Retina-ready Fast Consistent Hackable 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>
|
||||
18
frontend/render-badge-examples.js
Normal file
18
frontend/render-badge-examples.js
Normal 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
1884
lib/all-badge-examples.js
Normal file
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user