<div class="print-hide">
<h1>
Netrunner Proxy Generator
</h1>
<p>
Print Netrunner Proxy cards! Enter your card names into the sidebar, one card per line, and click print. <br />
Credits got to <a href="https://netrunnerdb.com/" title="NetrunnerDB">netrunnerdb.com</a> and <a href="http://cardgamedb.com/" title="Card Game DB">cardgamedb.com</a> for providing the API and images.
</p>
<p>
<a class="btn" href="javascript:window.print();" title="Print">Print Cards</a>
</p>
<textarea id="UserInput" name="UserInput" placeholder="Card Names" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus>
Exchange of Information
Desperado
The Toolbox
Grimoire
</textarea>
</div>
<div id="Cards"></div>
// card
$card-width: 6.35cm;
$card-height: 8.80cm;
$card-scale: 1;
// ui
$font-family-default: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
$font-family-mono: "Courier New", monospace;
$color-corp: #0A539D;
$color-runner: #B93A2F;
*,
*:before,
*:after {
box-sizing: border-box;
}
html,
html * {
font-family: $font-family-default;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #222;
}
body {
margin: 0;
background-color: white;
}
textarea { // sidebar
position: fixed;
top: 0;
left: 0;
width: 18rem;
height: 100vh;
padding: 3rem 1rem 6rem 1rem;
border: 0 none;
box-shadow: inset 0.4rem 0 0 darken($color-runner, 6%);
background-color: $color-runner;
color: white;
font-family: $font-family-mono;
font-size: 14px;
outline: none;
resize: none;
overflow-y: auto;
}
h1 {
margin: 3rem 0 1rem 0;
font-size: 1.75rem;
}
P {
margin: 1rem 0
}
strong, b {
font-weight: 600;
}
a {
color: $color-corp;
font-weight: 400;
text-decoration: underline;
}
.btn {
display: inline-block;
padding: 0.8em 1.4em;
border: 0 solid transparent;
border-radius: 2px;
box-shadow: 0 1px 4px rgba(black, 0.2);
// background: hsl(0, 0%, 92%) linear-gradient(to top, hsl(0, 15%, 90%) 0%, hsl(0, 10%, 96%) 100%);
background-color: $color-corp;
color: white;
line-height: 1;
text-decoration: none !important;
cursor: pointer;
background-position: center;
transition: background 0.125s;
&:hover {
background: $color-runner radial-gradient(circle, transparent 1%, $color-runner 1%) center/15000%;
}
&:active {
background-color: $color-corp;
background-size: 100%;
transition: background 0s;
}
}
img.card {
width: $card-width * $card-scale;
height: $card-height * $card-scale;
vertical-align: top;
border: 0.075cm solid black;
background-color: black;
}
#Cards,
#Cards > * {
line-height: 0;
}
.text-muted {
color: hsl(0, 0%, 62%);
}
[data-loading] {
display: inline-block;
font-size: 1rem;
line-height: 1;
padding: 1em;
}
@media print {
.print-hide {
display: none;
}
}
@media screen {
body {
margin: 0 1rem ($card-height / 2) 20rem;
overflow-y: scroll;
cursor: default;
}
#Cards {
margin-top: 3rem;
> * {
display: inline-block;
margin: 0;
vertical-align: top;
position: relative;
z-index: 10;
width: $card-width * $card-scale;
height: $card-height * $card-scale;
background: #f6f7f7 linear-gradient(-54deg, rgba(black, 0.06) 50%, rgba(black, 0.02) 50%);
transform: scale(1);
// filter: blur(0);
transition:
transform 0.125s,
filter 0.1s ease-in-out;
> img {
border-radius: 0.1cm;
background-image: none;
}
> img:after {
content: 'card';
padding: 1.621em 1rem;
line-height: 1.5;
}
> img:after,
> *:not(img) {
}
> .label {
visibility: hidden;
position: absolute;
left: 2px;
right: 2px;
bottom: 2px;
padding: 0.5em 1em;
border-radius: 0 0 0.1cm 0.1cm;
font-size: 12px;
line-height: 1.2;
background: rgba(black, 0.6);
color: white;
opacity: 0;
transition: opacity 0.1s;
}
}
> p {
padding: 1.621em 1rem;
line-height: 1.5;
}
> a:hover {
transform: scale(1.1);
z-index: 20;
> img {
}
> .label {
visibility: visible;
opacity: 1;
}
}
&:hover > a:not(:hover) img {
// filter: blur(0.5px) grayscale(0.5);
}
}
}
View Compiled
var _cardDB = {};
var _userInputElem = $('#UserInput');
var _cardListElem = $('#Cards');
var _cardListHtml = '';
// loadCards() load cardDB from local storage
function loadCards() {
_cardDB = localStorage.getItem('cards');
_cardDB = JSON.parse(_cardDB);
if (!_cardDB) {
fetchAllCards();
} else {
buildList();
}
}
// saveCards() save cardDB in local storage
function saveCards() {
localStorage.setItem('cards', JSON.stringify(_cardDB));
}
// reset alias
function reset() {
return fetchAllCards();
}
// fetchAllCards() get cards from api
function fetchAllCards() {
localStorage.removeItem('cards');
_cardListElem.html('<span class="text-muted" data-loading>loading cards ...</span>');
$.getJSON( "https://netrunnerdb.com/api/2.0/public/cards", function(response) {
_cardDB = {};
$.each(response.data, function(key, item) {
var image = 'https://netrunnerdb.com/card_image/' + item.code + '.png';
// console.log(item);
if (typeof item.image_url != "undefined") {
image = item.image_url;
}
/* TODO allow alt art for reprinted cards */
_cardDB[item.title.toLowerCase().replace(/:/g, '').replace(/\s/g, '__')] = {
code: item.code,
image: image
}
});
console.log('cards fetched from api');
saveCards();
buildList();
});
}
// buildList() generate image list
function buildList() {
var html = '';
var input = _userInputElem.val().toLowerCase().split(/\n/);
var unfound = 0;
if (!_cardDB) {
return false;
}
for (var i=0; i<input.length; i++) {
var cardname = $.trim(input[i]).replace(/:/g, '').replace(new RegExp(' ', 'g'), '__');
if (cardname == '') {
continue;
}
if (cardname in _cardDB) {
var card = _cardDB[cardname];
var newCard = '';
newCard += '<a href="https://netrunnerdb.com/en/card/' + card.code + '" title="" target="NetrunnerCard">';
newCard += '<img class="card" src="' + card.image + '" alt="' + card.code + '" />';
newCard += '<span class="label print-hide">' + card.code + ' ' + cardname.replace(/__/g, ' ') + '</span>';
newCard += '</a>';
// console.log(JSON.stringify(card) + ' ' + cardname);
// append
html += newCard;
// prepend
// html = newCard + html;
} else {
unfound++;
}
}
if (unfound > 0) {
html += '<p class="no-print text-muted">' + unfound + ' not found</p>';
}
if (_cardListHtml != html) {
// save current html
_cardListHtml = html;
// show images html
_cardListElem.html(_cardListHtml);
}
}
// assignEvents() rebuild image list when textarea changes
function assignEvents() {
$(document).on('input propertychange', _userInputElem, function() {
buildList();
});
}
assignEvents();
loadCards();
This Pen doesn't use any external CSS resources.