253 lines
10 KiB
JavaScript
Executable File
253 lines
10 KiB
JavaScript
Executable File
document.addEventListener("DOMContentLoaded", loadGames);
|
|
let elements = [];
|
|
let gameElements = [];
|
|
let topElements = [];
|
|
let isDev = [];
|
|
let pageData;
|
|
let starredGames = [];
|
|
let globalPlays = null;
|
|
|
|
function getHiddenGames() {
|
|
try {
|
|
const parsed = JSON.parse(localStorage.getItem("selenite.hiddenGames") || "[]");
|
|
return parsed;
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async function loadGames() {
|
|
if (type == "g") pageData = { path: "/resources/games-tagged.json", prefix: "semag", type: "g" };
|
|
else if (type == "a") pageData = { path: "/resources/apps.json", prefix: "sppa", type: "a" };
|
|
else { sAlert("this is not valid"); return; }
|
|
|
|
let data = await (await fetch(pageData.path)).json();
|
|
|
|
data.forEach((g, i) => { g._key = g.name.toUpperCase(); g._index = i; });
|
|
data.sort((a, b) => a._key < b._key ? -1 : a._key > b._key ? 1 : 0);
|
|
|
|
const gamesElement = document.getElementById("games");
|
|
const topGElement = document.getElementById("topGames");
|
|
const gamesFragment = document.createDocumentFragment();
|
|
const topFragment = document.createDocumentFragment();
|
|
|
|
const hiddenGames = pageData.type === "g" ? getHiddenGames() : [];
|
|
const hiddenSet = new Set(hiddenGames);
|
|
|
|
starredGames = JSON.parse(localStorage.getItem("selenite.starred") || "[]");
|
|
if (hiddenGames.length > 0) {
|
|
starredGames = starredGames.filter((game) => !hiddenSet.has(game));
|
|
localStorage.setItem("selenite.starred", JSON.stringify(starredGames));
|
|
}
|
|
const starredSet = new Set(starredGames);
|
|
|
|
data.forEach((element) => {
|
|
if (hiddenSet.has(element.directory)) return;
|
|
const isStarred = starredSet.has(element.directory);
|
|
const newElement = document.createElement("a");
|
|
newElement.dataset.target = element.directory;
|
|
newElement.dataset.image = element.image;
|
|
newElement.dataset.name = element._key;
|
|
newElement.dataset.top = element.tags && element.tags.includes("top") ? "1" : "";
|
|
newElement.dataset.index = element._index;
|
|
newElement.className = "game";
|
|
newElement.href = `/loader.html?title=${encodeURIComponent(element.name)}&dir=${element.directory}&img=${element.image}&type=${pageData.type}`;
|
|
|
|
const image = document.createElement("img");
|
|
image.src = `/resources/${pageData.prefix}/${element.directory}/${element.image}`;
|
|
image.loading = "lazy";
|
|
image.onerror = function() { this.src = "/img/missing.svg"; };
|
|
|
|
const holder = document.createElement("div");
|
|
holder.id = "holder";
|
|
const title = document.createElement("h1");
|
|
title.innerText = element.name;
|
|
holder.appendChild(title);
|
|
|
|
const star = document.createElement("img");
|
|
star.id = "star";
|
|
star.className = "star";
|
|
star.src = isStarred ? "/img/star-fill.svg" : "/img/star.svg";
|
|
|
|
const warnings = document.createElement("warnings");
|
|
newElement.appendChild(image);
|
|
newElement.appendChild(holder);
|
|
newElement.appendChild(warnings);
|
|
|
|
if (element.tags) {
|
|
[["18+", "thirteen", "18+"], ["13+", "thirteen", "13+"],
|
|
["horror", "horror", "😱"], ["gore", "gore", "🩸"]].forEach(([tag, cls, text]) => {
|
|
if (element.tags.includes(tag)) {
|
|
const w = document.createElement("warning");
|
|
w.innerText = text;
|
|
w.className = cls;
|
|
warnings.appendChild(w);
|
|
}
|
|
});
|
|
if (element.tags.includes("wip")) {
|
|
isDev.push(element.directory);
|
|
const w = document.createElement("warning");
|
|
w.innerText = "WIP";
|
|
w.className = "thirteen";
|
|
warnings.appendChild(w);
|
|
}
|
|
if (element.tags.includes("top")) {
|
|
topFragment.appendChild(newElement);
|
|
topElements.push(newElement);
|
|
} else {
|
|
gamesFragment.appendChild(newElement);
|
|
gameElements.push(newElement);
|
|
holder.appendChild(star);
|
|
}
|
|
} else {
|
|
gamesFragment.appendChild(newElement);
|
|
gameElements.push(newElement);
|
|
holder.appendChild(star);
|
|
}
|
|
|
|
elements.push(newElement);
|
|
star.addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
starEvent(e);
|
|
});
|
|
});
|
|
|
|
gamesElement.appendChild(gamesFragment);
|
|
if (topGElement) topGElement.appendChild(topFragment);
|
|
const visibleGameCount = elements.length;
|
|
const hiddenCount = hiddenGames.length;
|
|
document.getElementById("gameCount").innerText = hiddenCount > 0
|
|
? `${visibleGameCount} games loaded (${hiddenCount} hidden)`
|
|
: `${visibleGameCount} games loaded!`;
|
|
document.getElementById("loadingMsg").style.display = "none";
|
|
document.getElementById("allHeader").style.display = "block";
|
|
const topHeader = document.getElementById("topHeader");
|
|
if (topHeader && topElements.length > 0) topHeader.style.display = "block";
|
|
if (isDev.length > 0) console.log(isDev.join(","));
|
|
|
|
starredGames = JSON.parse(localStorage.getItem("selenite.starred") || "[]");
|
|
if (starredGames.length > 0) {
|
|
document.getElementById("starredHeader").style.display = "block";
|
|
_rebuildStarred();
|
|
document.querySelectorAll("#starredgames #star").forEach((e) => {
|
|
e.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); starEvent(e); });
|
|
});
|
|
}
|
|
}
|
|
|
|
let searchRaf = null;
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
document.getElementById("gamesearch").addEventListener("input", () => {
|
|
if (searchRaf) cancelAnimationFrame(searchRaf);
|
|
searchRaf = requestAnimationFrame(() => {
|
|
const input = document.getElementById("gamesearch").value.toUpperCase();
|
|
let hidden = 0;
|
|
elements.forEach((el) => {
|
|
if (el.dataset.name.includes(input)) {
|
|
el.style.display = "flex";
|
|
} else {
|
|
el.style.display = "none";
|
|
hidden++;
|
|
}
|
|
});
|
|
document.getElementById("noResults").style.display = hidden >= elements.length ? "flex" : "none";
|
|
searchRaf = null;
|
|
});
|
|
});
|
|
});
|
|
|
|
function _rebuildStarred() {
|
|
const container = document.getElementById("starredgames");
|
|
const gamesEl = document.getElementById("games");
|
|
container.innerHTML = "";
|
|
const fragment = document.createDocumentFragment();
|
|
starredGames.forEach((dir) => {
|
|
const el = gamesEl.querySelector(`a.game[data-target='${dir}']`);
|
|
if (el) fragment.appendChild(el.cloneNode(true));
|
|
});
|
|
container.appendChild(fragment);
|
|
}
|
|
|
|
function getTotalPlayTime(directory) {
|
|
const playTime = JSON.parse(localStorage.getItem("selenite.playTime") || "{}");
|
|
return Object.values(playTime).reduce((total, day) => total + (day[directory] || 0), 0);
|
|
}
|
|
|
|
function reSort(sortBy) {
|
|
const gamesEl = document.getElementById("games");
|
|
const topGEl = document.getElementById("topGames");
|
|
const topHeader = document.getElementById("topHeader");
|
|
|
|
if (sortBy === "az") {
|
|
if (topGEl) {
|
|
const frag = document.createDocumentFragment();
|
|
topElements.forEach(el => frag.appendChild(el));
|
|
topGEl.appendChild(frag);
|
|
if (topHeader && topElements.length > 0) topHeader.style.display = "block";
|
|
}
|
|
const sorted = [...gameElements].sort((a, b) => a.dataset.name < b.dataset.name ? -1 : a.dataset.name > b.dataset.name ? 1 : 0);
|
|
const frag = document.createDocumentFragment();
|
|
sorted.forEach(el => frag.appendChild(el));
|
|
gamesEl.appendChild(frag);
|
|
return;
|
|
}
|
|
|
|
if (topHeader) topHeader.style.display = "none";
|
|
const all = [...gameElements, ...topElements];
|
|
if (sortBy === "za") {
|
|
all.sort((a, b) => a.dataset.name > b.dataset.name ? -1 : a.dataset.name < b.dataset.name ? 1 : 0);
|
|
} else if (sortBy === "played") {
|
|
all.sort((a, b) => getTotalPlayTime(b.dataset.target) - getTotalPlayTime(a.dataset.target));
|
|
} else if (sortBy === "global") {
|
|
if (!globalPlays) return;
|
|
all.sort((a, b) => (globalPlays.get(b.dataset.target) || 0) - (globalPlays.get(a.dataset.target) || 0));
|
|
} else if (sortBy === "new") {
|
|
all.sort((a, b) => a.dataset.index - b.dataset.index);
|
|
}
|
|
const fragment = document.createDocumentFragment();
|
|
all.forEach(el => fragment.appendChild(el));
|
|
gamesEl.appendChild(fragment);
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
const sortSelect = document.getElementById("gamesort");
|
|
if (!sortSelect) return;
|
|
sortSelect.addEventListener("change", async () => {
|
|
if (sortSelect.value === "global" && !globalPlays) {
|
|
sortSelect.disabled = true;
|
|
try {
|
|
const data = await (await fetch("/api/analytics/get")).json();
|
|
globalPlays = new Map(data.map(e => [e.name, e.plays]));
|
|
} finally {
|
|
sortSelect.disabled = false;
|
|
}
|
|
}
|
|
reSort(sortSelect.value);
|
|
});
|
|
});
|
|
|
|
function starEvent(e) {
|
|
const game = e.target.parentNode.parentNode.getAttribute("data-target");
|
|
starredGames = JSON.parse(localStorage.getItem("selenite.starred") || "[]");
|
|
const header = document.getElementById("starredHeader");
|
|
|
|
if (starredGames.indexOf(game) == -1) {
|
|
starredGames.push(game);
|
|
starredGames.sort();
|
|
header.style.display = "block";
|
|
e.target.src = "/img/star-fill.svg";
|
|
} else {
|
|
starredGames.splice(starredGames.indexOf(game), 1);
|
|
document.querySelectorAll(`a.game[data-target='${game}'] #star`).forEach((s) => { s.src = "/img/star.svg"; });
|
|
header.style.display = starredGames.length > 0 ? "block" : "none";
|
|
}
|
|
|
|
localStorage.setItem("selenite.starred", JSON.stringify(starredGames));
|
|
_rebuildStarred();
|
|
|
|
document.querySelectorAll("#starredgames #star").forEach((e) => {
|
|
e.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); starEvent(e); });
|
|
});
|
|
}
|