More work on cube html

This commit is contained in:
Hamcha 2019-11-22 11:47:27 +01:00
parent 9953f6c289
commit e7e7426da1
Signed by: hamcha
GPG key ID: 44AD3571EB09A39E
3 changed files with 182 additions and 23 deletions

View file

@ -2,11 +2,23 @@ import * as ejs from "ejs";
import { existsSync } from "fs";
import { createServer } from "http";
import { Article, asyncLoadJSON, CardItem, leanArticle, leanCard, MCMDB, onlyUnique } from "../lib";
import {
Article,
asyncLoadJSON,
CardItem,
dictMap,
filterDict,
leanArticle,
leanCard,
MCMDB,
onlyUnique,
spanBy,
} from "../lib";
const colorNames = {
CL: "Colorless",
MC: "Multicolor",
L: "Land",
W: "White",
U: "Blue",
B: "Black",
@ -35,13 +47,14 @@ const colorNames = {
};
const columns: Record<string, (c: CardItem) => boolean> = {
W: c => colorid(c.colorIdentity) == "W",
U: c => colorid(c.colorIdentity) == "U",
B: c => colorid(c.colorIdentity) == "B",
R: c => colorid(c.colorIdentity) == "R",
G: c => colorid(c.colorIdentity) == "G",
MC: c => c.colorIdentity.length > 0,
CL: c => colorid(c.colorIdentity) == "CL"
W: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "W",
U: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "U",
B: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "B",
R: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "R",
G: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "G",
MC: c => c.types[0] != "Land" && c.colorIdentity.length > 1,
CL: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "CL",
L: c => c.types[0] == "Land"
};
function wubrg(a: string, b: string) {
@ -58,6 +71,53 @@ function colorid(colors: string[]): string {
return colors.sort(wubrg).join("");
}
function prettyColor(color: string) {
if (color in colorNames) {
return colorNames[color];
}
return color;
}
const allTypes = [
"Creature",
"Planeswalker",
"Instant",
"Sorcery",
"Artifact",
"Enchantment"
];
function typeSort(a: string, b: string): number {
const indexA = allTypes.indexOf(a);
const indexB = allTypes.indexOf(b);
return indexA - indexB;
}
function abcSort(a: string, b: string): number {
if (a > b) {
return 1;
}
if (b > a) {
return -1;
}
return 0;
}
// This would be properly typed but as of currently TS does not allow circular references for types
function deepSum(dict: any): number {
if (Array.isArray(dict)) {
return dict.length;
}
let total = 0;
for (let key in dict) {
if (Array.isArray(dict[key])) {
total += dict[key].length;
} else {
total += deepSum(dict[key]);
}
}
return total;
}
async function run() {
if (process.argv.length < 3) {
console.error("Usage: yarn fetch <uid>");
@ -96,15 +156,27 @@ async function run() {
)
.filter(onlyUnique);
// Filter by colors and cmc (nested)
let colorcards = filterDict(valid, columns);
let cmccards = dictMap(colorcards, (cards, col) =>
dictMap(
spanBy(cards, c =>
col == "MC" || col == "L" ? colorid(c.colorIdentity) : c.types[0]
),
typed => spanBy(typed, c => c.convertedManaCost)
)
);
const server = createServer(async (req, res) => {
const template = await ejs.renderFile("templates/cube.ejs", {
user: uid,
cards: valid,
cmccards,
columns,
utils: { wubrg, colorNames, colorid }
utils: { wubrg, prettyColor, colorid, deepSum, typeSort, abcSort }
});
res.end(template);
});
server.on("clientError", (err, socket) => {
socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
});

View file

@ -61,3 +61,41 @@ export function leanArticle(article: Article): LeanArticle {
export function onlyUnique(value: CardItem, index: number, self: CardItem[]) {
return self.findIndex(c => c.name == value.name) == index;
}
export function filterDict<K extends keyof any, T>(
arr: T[],
list: Record<K, (i: T) => boolean>
): Record<K, T[]> {
let out: Record<K, T[]> = Object.create(null);
for (const key in list) {
out[key] = arr.filter(list[key]);
}
return out;
}
export function spanBy<K extends keyof any, T>(
arr: T[],
spanFn: (i: T) => K
): Record<K, T[]> {
let out: Record<K, T[]> = Object.create(null);
arr.forEach(item => {
let key = spanFn(item);
if (key in out) {
out[key].push(item);
} else {
out[key] = [item];
}
});
return out;
}
export function dictMap<K extends keyof any, A, B>(
dict: Record<K, A>,
mapFn: (i: A, k: K) => B
): Record<K, B> {
let out: Record<K, B> = Object.create(null);
for (let key in dict) {
out[key] = mapFn(dict[key], key);
}
return out;
}

View file

@ -10,7 +10,7 @@
main {
background: white;
max-width: 920px;
max-width: 1220px;
margin: 0 auto;
padding: 20pt;
}
@ -33,58 +33,107 @@
.color-section {
flex: 1;
margin: 5px;
}
.color-section header {
text-align: center;
}
.color-W header {
.color-W header.color-header {
background-color: #fff6eb;
}
.color-U header {
.color-U header.color-header {
background-color: #49b0fd;
}
.color-B header {
.color-B header.color-header {
background-color: #666;
color: white;
}
.color-R header {
.color-R header.color-header {
background-color: #ff6868;
}
.color-G header {
.color-G header.color-header {
background-color: #78ce59;
}
.color-MC header {
.color-MC header.color-header {
background: linear-gradient(to left, #f3ff6b, #ffb019);
}
.color-CL header {
.color-CL header.color-header {
background-color: #d2d2d2;
}
.color-L header.color-header {
background-color: #eeb445;
}
.type-section {
border: 1px solid #aaa;
border-radius: 5px;
font-size: 10pt;
margin: 5px 0;
}
.type-section header.type-header {
font-size: 12pt;
font-weight: bold;
border-bottom: 1px solid #ccc;
padding: 5px;
}
ul {
margin: 0;
padding: 0;
list-style-type: none;
border-bottom: 1px solid #ccc;
}
ul li {
padding: 5px;
}
ul:last-child {
border-bottom: none;
}
</style>
</head>
<body>
<main>
<header>
<h1>Junk rare cube</h1>
<h1>Junk rare cube (<%=cards.length%> cards)</h1>
<h2>Using cards from <a href="https://www.cardmarket.com/en/Magic/Users/<%=user%>"><b><%= user %></b></a>
</h2>
</header>
<section class="columns">
<% for (const column in columns) { %>
<section class="color-section color-<%=column%>">
<header>
<h3><%=utils.colorNames[column]%></h3>
<% Object.entries(cmccards).forEach(([color, colorcards]) => { %>
<section class="color-section color-<%=color%>">
<header class="color-header">
<h3><%=utils.prettyColor(color)%> (<%=utils.deepSum(colorcards)%>)</h3>
</header>
<% Object.entries(colorcards).sort((a, b) => color == "MC" || color == "L" ? utils.abcSort(a[0], b[0]) : utils.typeSort(a[0], b[0])).forEach(([type, typecards]) => { %>
<article class="type-section">
<header class="type-header"><%= color == "MC" || color == "L" ? utils.prettyColor(type) : type %>
(<%=utils.deepSum(typecards)%>)</header>
<section class="cards">
<% Object.entries(typecards).forEach(([cmc, finalcards]) => { %>
<ul>
<% finalcards.forEach(card => { %>
<li><%= card.name %></li>
<% }); %>
</ul>
<% }); %>
</section>
<% } %>
</article>
<% }); %>
</section>
<% }); %>
</section>
</main>
</body>