More work on cube html
This commit is contained in:
parent
9953f6c289
commit
e7e7426da1
3 changed files with 182 additions and 23 deletions
|
@ -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");
|
||||
});
|
||||
|
|
38
lib/utils.ts
38
lib/utils.ts
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue