mirror of
https://github.com/cfultz/mtgcsv.git
synced 2024-11-21 17:00:04 +01:00
Initial
This commit is contained in:
commit
ba4a7638c0
149
app.js
Normal file
149
app.js
Normal file
@ -0,0 +1,149 @@
|
||||
let cardList = [];
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const toggle = document.getElementById('dark-mode-toggle');
|
||||
|
||||
toggle.addEventListener('change', () => {
|
||||
if (toggle.checked) {
|
||||
document.documentElement.classList.add('dark-mode');
|
||||
localStorage.setItem('theme', 'dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark-mode');
|
||||
localStorage.setItem('theme', 'light');
|
||||
}
|
||||
});
|
||||
|
||||
// Load the saved theme preference
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme === 'dark') {
|
||||
document.documentElement.classList.add('dark-mode');
|
||||
toggle.checked = true;
|
||||
}
|
||||
});
|
||||
|
||||
async function fetchCardSuggestions(query) {
|
||||
const response = await fetch(`https://api.scryfall.com/cards/autocomplete?q=${encodeURIComponent(query)}`);
|
||||
const data = await response.json();
|
||||
return data.data;
|
||||
}
|
||||
|
||||
document.getElementById('card-name').addEventListener('input', async function() {
|
||||
const query = this.value;
|
||||
const suggestions = await fetchCardSuggestions(query);
|
||||
const suggestionsDiv = document.getElementById('suggestions');
|
||||
suggestionsDiv.innerHTML = '';
|
||||
suggestions.forEach(suggestion => {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = suggestion;
|
||||
div.onclick = () => {
|
||||
document.getElementById('card-name').value = suggestion;
|
||||
suggestionsDiv.innerHTML = '';
|
||||
};
|
||||
suggestionsDiv.appendChild(div);
|
||||
});
|
||||
});
|
||||
|
||||
async function fetchCardDetails(cardName, setCode) {
|
||||
const response = await fetch(`https://api.scryfall.com/cards/named?exact=${encodeURIComponent(cardName)}&set=${encodeURIComponent(setCode)}`);
|
||||
const data = await response.json();
|
||||
return {
|
||||
mana_cost: data.mana_cost || 'N/A',
|
||||
power: data.power || 'N/A',
|
||||
toughness: data.toughness || 'N/A',
|
||||
type: data.type_line.split('—')[0].trim(), // Remove anything after em dash
|
||||
rarity: data.rarity || 'N/A'
|
||||
};
|
||||
}
|
||||
|
||||
async function addCard() {
|
||||
const cardName = document.getElementById('card-name').value;
|
||||
const setCode = document.getElementById('set-code').value;
|
||||
const cardId = document.getElementById('card-id').value;
|
||||
const quantity = document.getElementById('quantity').value;
|
||||
const foil = document.getElementById('foil').value;
|
||||
|
||||
const cardDetails = await fetchCardDetails(cardName, setCode);
|
||||
|
||||
const cardData = {
|
||||
name: cardName,
|
||||
set: setCode,
|
||||
card_id: cardId,
|
||||
quantity: quantity,
|
||||
foil: foil,
|
||||
mana_type: cardDetails.mana_cost,
|
||||
power: cardDetails.power,
|
||||
toughness: cardDetails.toughness,
|
||||
type: cardDetails.type,
|
||||
rarity: cardDetails.rarity
|
||||
};
|
||||
|
||||
cardList.push(cardData);
|
||||
|
||||
// Update the textarea with the new card information
|
||||
let csvContent = generateCSVContent();
|
||||
document.getElementById('csv-output').value = csvContent;
|
||||
|
||||
// Show the card image in the dissolving popup
|
||||
showCardPopup(cardName, setCode);
|
||||
}
|
||||
|
||||
function generateCSVContent() {
|
||||
let csvContent = "Card Name,Set,Card ID,Quantity,Foil,Mana Type,Power,Toughness,Type,Rarity\n";
|
||||
cardList.forEach(card => {
|
||||
const escapedValues = [
|
||||
card.name,
|
||||
card.set,
|
||||
card.card_id,
|
||||
card.quantity,
|
||||
card.foil,
|
||||
card.mana_type,
|
||||
card.power,
|
||||
card.toughness,
|
||||
card.type,
|
||||
card.rarity
|
||||
].map(value => `"${value.replace(/"/g, '""')}"`); // Escape any existing quotes by doubling them
|
||||
csvContent += escapedValues.join(",") + "\n";
|
||||
});
|
||||
return csvContent;
|
||||
}
|
||||
|
||||
async function showCardPopup(cardName, setCode) {
|
||||
const cardPopup = document.getElementById('card-popup');
|
||||
const response = await fetch(`https://api.scryfall.com/cards/named?exact=${encodeURIComponent(cardName)}&set=${encodeURIComponent(setCode)}`);
|
||||
const data = await response.json();
|
||||
const imageUrl = data.image_uris ? data.image_uris.small : null;
|
||||
|
||||
if (imageUrl) {
|
||||
cardPopup.innerHTML = `<img src="${imageUrl}" alt="${cardName}">`;
|
||||
cardPopup.style.display = 'block';
|
||||
cardPopup.style.opacity = 1;
|
||||
|
||||
// Dissolve the popup after a few seconds
|
||||
setTimeout(() => {
|
||||
cardPopup.style.opacity = 0;
|
||||
setTimeout(() => {
|
||||
cardPopup.style.display = 'none';
|
||||
}, 500);
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
function downloadCSV() {
|
||||
const csvContent = generateCSVContent();
|
||||
|
||||
// Create a blob with the CSV content
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create a temporary link element
|
||||
const link = document.createElement("a");
|
||||
link.setAttribute("href", url);
|
||||
link.setAttribute("download", "mtg_cards.csv");
|
||||
document.body.appendChild(link);
|
||||
|
||||
// Trigger the download
|
||||
link.click();
|
||||
|
||||
// Clean up and remove the link
|
||||
document.body.removeChild(link);
|
||||
}
|
47
index.html
Normal file
47
index.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MTG Card CSV Generator</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Sorts+Mill+Goudy&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>MTG Card CSV Generator</h1>
|
||||
<form id="card-form">
|
||||
<div>
|
||||
<label for="card-name">Card Name:</label>
|
||||
<input type="text" id="card-name" autocomplete="off" required>
|
||||
<div id="suggestions"></div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="set-code">Set Code:</label>
|
||||
<input type="text" id="set-code" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="card-id">Card ID:</label>
|
||||
<input type="text" id="card-id" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="quantity">Quantity:</label>
|
||||
<input type="number" id="quantity" min="1" value="1" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="foil">Is it Foil?</label>
|
||||
<select id="foil">
|
||||
<option value="No">No</option>
|
||||
<option value="Yes">Yes</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" onclick="addCard()">Add Card</button>
|
||||
</form>
|
||||
<button onclick="downloadCSV()">Download CSV</button>
|
||||
<textarea id="csv-output" readonly></textarea>
|
||||
<div id="card-popup" class="card-popup"></div>
|
||||
</div>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
22
manifest.json
Normal file
22
manifest.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "MTG Card CSV Generator",
|
||||
"short_name": "MTG CSV",
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"background_color": "#cc5200",
|
||||
"theme_color": "#007acc",
|
||||
"description": "A PWA for generating CSV files with Magic: The Gathering card details",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icon.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "icon.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
22
service-worker.js
Normal file
22
service-worker.js
Normal file
@ -0,0 +1,22 @@
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
caches.open('mtg-csv-generator-v1').then((cache) => {
|
||||
return cache.addAll([
|
||||
'/',
|
||||
'/index.html',
|
||||
'/styles.css',
|
||||
'/app.js',
|
||||
'/manifest.json',
|
||||
'/icon.png'
|
||||
]);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
event.respondWith(
|
||||
caches.match(event.request).then((response) => {
|
||||
return response || fetch(event.request);
|
||||
})
|
||||
);
|
||||
});
|
115
styles.css
Normal file
115
styles.css
Normal file
@ -0,0 +1,115 @@
|
||||
:root {
|
||||
--background-color: #f0f0f0;
|
||||
--text-color: #333;
|
||||
--card-background: #ffffff;
|
||||
--button-background: #007acc;
|
||||
--button-hover: #005fa3;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background-color: #1e1e1e;
|
||||
--text-color: #ffffff;
|
||||
--card-background: #2e2e2e;
|
||||
--button-background: #1f6fb2;
|
||||
--button-hover: #145b8c;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background-color: var(--card-background);
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
font-family: 'Sorts Mill Goudy', serif;
|
||||
}
|
||||
|
||||
form div {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
input, select, textarea {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
background-color: var(--card-background);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: var(--button-background);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: var(--button-hover);
|
||||
}
|
||||
|
||||
#csv-output {
|
||||
margin-top: 20px;
|
||||
height: 200px;
|
||||
background-color: var(--card-background);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.card-popup {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
max-width: 20%;
|
||||
z-index: 1000;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card-popup img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.card-popup {
|
||||
max-width: 40%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 400px) {
|
||||
.card-popup {
|
||||
max-width: 60%;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user