jillo-bot/static/create-recipe/script.js

145 lines
3.9 KiB
JavaScript

let resolveLoaded;
const loaded = new Promise(resolve => resolveLoaded = resolve);
function e(unsafeText) {
let div = document.createElement('div');
div.innerText = unsafeText;
return div.innerHTML;
}
/**
* @type {import('../../src/lib/rpg/items').Item | null}
*/
let draggedItem = null;
/**
* @type {Record<string, import('../../src/lib/rpg/items').Items[]>}
*/
let itemLists = {};
function listToString(list) {
return list.map(stack => `${stack.item.id},${stack.quantity}`).join(';');
}
function updateString() {
document.querySelector('#recipe-string').innerText = [
listToString(itemLists['inputs'] || []),
listToString(itemLists['requirements'] || []),
listToString(itemLists['outputs'] || []),
].join('|');
}
/**
* @param {import('../../src/lib/rpg/items').Item} item
*/
function renderItem(item) {
const i = document.createElement('div');
i.innerHTML = `
<div class="icon">
${e(item.emoji)}
</div>
<div class="right">
<div class="name">${e(item.name)}</div>
<div class="description">${item.description ? e(item.description) : '<i>No description</i>'}</div>
</div>
`;
i.classList.add('item');
i.draggable = true;
i.addEventListener('dragstart', event => {
draggedItem = item;
event.target.classList.add('dragging');
});
i.addEventListener('dragend', event => {
draggedItem = null;
event.target.classList.remove('dragging');
});
return i;
}
function renderItemStack(item, quantity, type) {
const i = document.createElement('div');
i.innerHTML = `
<div class="icon">
${e(item.emoji)}
</div>
<div class="right">
x<b>${quantity}</b>
</div>
`;
i.classList.add('itemstack');
i.draggable = true;
i.addEventListener('dragstart', event => {
event.target.classList.add('dragging');
});
i.addEventListener('dragend', event => {
event.target.classList.remove('dragging');
itemLists[type] = itemLists[type] || [];
const items = itemLists[type];
const stackIdx = items.findIndex(n => n.item.id === item.id);
if (stackIdx !== -1) items.splice(stackIdx, 1);
document.querySelector(`.item-list[data-type="${type}"]`).replaceWith(renderItemList(items, type));
updateString();
});
return i;
}
function renderItemList(items, type) {
const i = document.createElement('div');
i.textContent = '';
items.forEach(itemStack => {
i.appendChild(renderItemStack(itemStack.item, itemStack.quantity, type));
});
i.dataset.type = type;
i.classList.add('item-list');
// prevent default to allow drop
i.addEventListener('dragover', (event) => event.preventDefault(), false);
i.addEventListener('dragenter', event => draggedItem && event.target.classList.add('dropping'));
i.addEventListener('dragleave', event => draggedItem && event.target.classList.remove('dropping'));
i.addEventListener('drop', (event) => {
event.preventDefault();
event.target.classList.remove('dropping');
if (!draggedItem) return;
itemLists[type] = itemLists[type] || [];
const items = itemLists[type];
const itemStack = items.find(v => v.item.id === draggedItem.id);
if (!itemStack) {
items.push({
item: draggedItem,
quantity: 1
});
} else {
itemStack.quantity = itemStack.quantity + 1;
}
updateString();
draggedItem = null;
event.target.replaceWith(renderItemList(items, type));
});
return i;
}
Promise.all([
fetch(`/api/items${document.location.search}`)
.then(res => res.json()),
loaded
]).then(([items]) => {
const itemsContainer = document.querySelector('.items');
itemsContainer.textContent = '';
items.forEach(item =>
itemsContainer.appendChild(renderItem(item))
);
document.querySelectorAll('.item-list').forEach(elem => {
const type = elem.dataset.type;
elem.replaceWith(renderItemList([], type));
});
updateString();
});
document.addEventListener('DOMContentLoaded', () => resolveLoaded());