Decklist Aggregator

by Cody Bennett

HTML

<script src="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&amp;display=swap"></script>
<main>
  <header>
    <h1>Decklist Aggregator</h1>
  </header>
  <section>
    <h2>Select decklist files</h2>
    <input type="file" id="decks" name="decks" multiple="multiple" />
  </section>
  <section>
    <h2>Generated deck</h2>
    <textarea id="aggregated-deck" rows="10"></textarea>
  </section>
  <section>
    <p>
      <button type="button" id="download">Download Deck</button>
    </p>
  </section>
</main>

CSS

*,
*::before,
*::after {
  box-sizing: inherit;
  color: inherit;
  font-family: inherit;
  margin: 0;
  padding: 0;
}

body {
  color: rgb(17 17 17 / 0.8);
  font-family: 'Montserrat', sans-serif;
}

h1, h2, button {
  color: #111;
  font-weight: 700;
}

h1 {
  text-align: center;
}

h2 {
  font-size: 1em;
}

button {
  background: none;
  border: none;
  cursor: pointer;
  outline: none;
  text-decoration: underline;
}

textarea {
  width: 100%;
}

p {
  text-align: justify;
}

a {
  color: #4457c9;
  text-decoration: none;
}

main {
  display: grid;
  grid-gap: 16px;
  margin: 16px auto;
  max-width: 696px;
}

@media only screen and (max-width: 696px) {
  main {
    max-width: 90%;
  }
}

JavaScript

function parseFile(file) {
  const cardsWithTotals = file.split('\n');
  const main = {};
  const sideboard = {};
  let isSideboard = false;

  for (let i = 0; i < cardsWithTotals.length; i++) {
    const cardWithTotal = cardsWithTotals[i].trim();
    if (!cardWithTotal || cardWithTotal === 'Sideboard') {
      isSideboard = true;
      continue;
    }

    const card = cardWithTotal.match(/(\d+)\s+(.*)/);
    if (!card) return false;

    const total = card[1];
    const cardName = card[2];
    if (isSideboard) {
      sideboard[cardName] = parseInt(total);
    } else {
      main[cardName] = parseInt(total);
    }
  }
  return {
    main,
    sideboard
  };
}

function numberedCards(cards) {
  const numbered = [];

  for (const card in cards) {
    for (let i = 1; i <= cards[card]; i++) {
      numbered.push(`${i} ${card}`);
    }
  }

  return numbered;
}

function sumCards(allCards, deck) {
  for (let i = 0; i < deck.length; i++) {
    const card = deck[i];
    if (!allCards[card]) allCards[card] = 0;

    allCards[card]++;
  }

  return allCards;
}

function sortCards(cards) {
  const list = [];

  for (const card in cards) {
    const auxCard = card.split(/(\d+) (.*)/);
    list.push({
      total: cards[card],
      name: auxCard[2],
      number: auxCard[1],
    });
  }

  return list.sort((a, b) => b.total - a.total);
}

function aggregateDeck(cards, limit) {
  let total = 0,
    card;
  const deck = {};

  for (let i = 0; i < cards.length; i++) {
    card = cards[i].name;
    if (!deck[card]) deck[card] = 0;

    deck[card]++;
    total++;
    if (total >= limit) break;
  }

  const deckAsArray = [];

  for (card in deck) {
    deckAsArray.push({
      total: deck[card],
      card
    });
  }

  return deckAsArray;
}

function printDeck(main, sideboard) {
  return `${printCards(main)}\n${printCards(sideboard)}`
}

function printCards(cards) {
  let output = '';

  for (let i = 0; i < cards.length; i++) {
    output += cards[i].total + ' ' +...