From 7596d7283de25374775c3cdacf3031010bb9a94f Mon Sep 17 00:00:00 2001 From: sky Date: Fri, 14 Nov 2025 21:53:45 -0500 Subject: [PATCH] mobile support and shit --- css/games.css | 10 ++ css/loader.css | 12 +++ css/sidebar.css | 46 ++++++-- css/users.css | 10 ++ index.html | 23 ++-- js/games_improved.js | 243 +++++++++++++++++++++++++++++++++++++++++++ projects.html | 3 - projects_opt.html | 43 ++++++++ settings.html | 48 ++++++--- sw.js | 72 ++++++------- 10 files changed, 436 insertions(+), 74 deletions(-) create mode 100644 js/games_improved.js create mode 100755 projects_opt.html diff --git a/css/games.css b/css/games.css index 0506a9c..c1d2b28 100755 --- a/css/games.css +++ b/css/games.css @@ -112,4 +112,14 @@ warning { body[fast] game { background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%); backdrop-filter: blur(0); +} +@media screen and (max-width: 900px) { + game { + width: 40vw; + } +} +@media screen and (max-width: 660px) { + game { + width: 60vw; + } } \ No newline at end of file diff --git a/css/loader.css b/css/loader.css index 3522f8f..8b0e20a 100644 --- a/css/loader.css +++ b/css/loader.css @@ -57,4 +57,16 @@ body { body[fast] #gamecontainer { background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%); backdrop-filter: blur(0); +} +@media screen and (max-width: 660px) { + #infobox h2 { + max-width: 45%; + font-size: 16px; + } + .button { + width: 22%; + margin: 0.5%; + aspect-ratio: 1 / 1; + border-radius: 8px; + } } \ No newline at end of file diff --git a/css/sidebar.css b/css/sidebar.css index 4ce9918..69690cd 100755 --- a/css/sidebar.css +++ b/css/sidebar.css @@ -1,5 +1,6 @@ -body { - overflow: hidden; +html,body { + overflow: hidden; + height: 100%; } sidebar { background-color: linear-gradient(19deg,rgba(87, 199, 133, 1) 0%, rgba(237, 221, 83, 1) 100%);; @@ -29,13 +30,10 @@ iframe { } .sidebar-divider { - height: 2px; - border-radius: 20px; - width: 80%; background-color: #ffffff22; /* auto is being stupid 100vh minus height of 1 object 7 times minus the margin and padding of 7 objects (multiplied twice bc margin and padding on top and bottom) */ - margin-bottom: calc(100vh - 26px * 8 - ((6px + 6px) * 2) * 8); + margin-bottom: calc(100vh - 26px * 9 - ((6px + 6px) * 2) * 9); } .sidebar-item-descriptor { @@ -144,4 +142,40 @@ alert p { opacity: 0; top: -50px; } +} +#fullscreen { + display: none; +} +@media screen and (max-width: 660px) { + sidebar { + height: 50px; + width: 100vw; + display: flex; + flex-direction: row; + align-items: center; + user-select: none; + z-index: 10; + overflow: scroll; + justify-content: center; + } + iframe { + width: calc(100% - 20px); + height: calc(100% - 50px - 20px); + margin: 10px; + margin-right: 0px; + border-radius: 8px; + } + body { + display: flex; + flex-direction: column-reverse; + } + #bottom-menu, #open-bottom-menu, .sidebar-item-descriptor { + display: none; + } + #openblank { + display: none; + } + #fullscreen { + display: block; + } } \ No newline at end of file diff --git a/css/users.css b/css/users.css index 446e8f3..45b0ebd 100644 --- a/css/users.css +++ b/css/users.css @@ -56,4 +56,14 @@ body[fast] .users { background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%); backdrop-filter: blur(0); +} +@media screen and (max-width: 900px) { + .users { + width: 40vw; + } +} +@media screen and (max-width: 660px) { + .users { + width: 80vw; + } } \ No newline at end of file diff --git a/index.html b/index.html index dae65a2..75e1f24 100755 --- a/index.html +++ b/index.html @@ -10,7 +10,6 @@ - @@ -41,16 +40,6 @@ - Selenite @@ -240,7 +229,10 @@ location.href = "https://google.com"; window.close(); }) - + } else if(item.childNodes[0].id == "fullscreen") { + item.childNodes[0].addEventListener("click", (e)=>{ + document.getElementById("iframe").requestFullscreen(); + }) } }) document.getElementById("open-bottom-menu").addEventListener("click", ()=>{ @@ -266,6 +258,7 @@ + @@ -279,5 +272,11 @@

|

7:41:21 pm

+
+

Johnson Education

+ +

Educational Resources for Students

+

Science Textbooks

+
diff --git a/js/games_improved.js b/js/games_improved.js new file mode 100644 index 0000000..b59139f --- /dev/null +++ b/js/games_improved.js @@ -0,0 +1,243 @@ +// this IS ai generated +// wanna test real world difference soon + +document.addEventListener("DOMContentLoaded", loadGames); + +let elements = []; +let isDev = []; +let starredGames = []; + +// Cache DOM references +const domCache = { + games: null, + topGames: null, + starredGames: null, + gameCount: null, + loadingMsg: null, + allHeader: null, + topHeader: null, + starredHeader: null, + noResults: null, + gameSearch: null +}; + +function initDOMCache() { + domCache.games = document.getElementById("games"); + domCache.topGames = document.getElementById("topGames"); + domCache.starredGames = document.getElementById("starredgames"); + domCache.gameCount = document.getElementById("gameCount"); + domCache.loadingMsg = document.getElementById("loadingMsg"); + domCache.allHeader = document.getElementById("allHeader"); + domCache.topHeader = document.getElementById("topHeader"); + domCache.starredHeader = document.getElementById("starredHeader"); + domCache.noResults = document.getElementById("noResults"); + domCache.gameSearch = document.getElementById("gamesearch"); +} + +async function loadGames() { + initDOMCache(); + + // Load starred games once + starredGames = JSON.parse(localStorage.getItem("selenite.starred") || '[]'); + + // Fetch and sort games + const data = await (await fetch("/resources/games.json")).json(); + const sorted = data.sort((a, b) => { + const n1 = a.name.toUpperCase(); + const n2 = b.name.toUpperCase(); + return n1 < n2 ? -1 : n1 > n2 ? 1 : 0; + }); + + // Use DocumentFragments for batched DOM operations + const gamesFragment = document.createDocumentFragment(); + const topGamesFragment = document.createDocumentFragment(); + + sorted.forEach(element => { + const isStarred = starredGames.includes(element.directory); + const newElement = createGameElement(element, isStarred); + elements.push(newElement); + + if (element.tags?.includes("top")) { + topGamesFragment.appendChild(newElement); + } else { + gamesFragment.appendChild(newElement); + } + + if (element.tags?.includes("tofinish")) { + isDev.push(element.directory); + } + }); + + // Append all elements at once (2 reflows instead of N) + domCache.games.appendChild(gamesFragment); + domCache.topGames.appendChild(topGamesFragment); + + // Update UI + domCache.gameCount.innerText = `${data.length} games loaded!`; + domCache.loadingMsg.style.display = "none"; + domCache.allHeader.style.display = "block"; + domCache.topHeader.style.display = "block"; + + if (isDev.length > 0) { + sAlert("wip games", "dev message, shouldnt be seen"); + console.log(isDev.join(",")); + } + + // Render starred games if any + if (starredGames.length > 0) { + renderStarredGames(); + } + + // Setup event delegation for game clicks and stars + setupEventDelegation(); +} + +function createGameElement(element, isStarred) { + const newElement = document.createElement("game"); + newElement.setAttribute("data-target", element.directory); + newElement.setAttribute("data-image", element.image); + newElement.setAttribute("data-name", element.name); + + const image = document.createElement("img"); + image.src = `/resources/semag/${element.directory}/${element.image}`; + image.loading = "lazy"; + + const holder = document.createElement("div"); + holder.id = "holder"; + + const title = document.createElement("h1"); + title.innerText = element.name; + + const warnings = document.createElement("warnings"); + + // Add warning tags if present + if (element.tags) { + if (element.tags.includes("13+")) { + const thirteenplus = document.createElement("warning"); + thirteenplus.innerText = "13+"; + thirteenplus.classList = "thirteen"; + warnings.appendChild(thirteenplus); + } + if (element.tags.includes("horror")) { + const horror = document.createElement("warning"); + horror.innerText = "😱"; + horror.classList = "horror"; + warnings.appendChild(horror); + } + if (element.tags.includes("gore")) { + const gore = document.createElement("warning"); + gore.innerText = "🩸"; + gore.classList = "gore"; + warnings.appendChild(gore); + } + } + + // Only add star for non-top games + if (!element.tags?.includes("top")) { + const star = document.createElement("img"); + star.id = "star"; + star.classList = "star"; + star.src = isStarred ? "/img/star-fill.svg" : "/img/star.svg"; + holder.appendChild(title); + holder.appendChild(star); + } else { + holder.appendChild(title); + } + + newElement.appendChild(image); + newElement.appendChild(holder); + newElement.appendChild(warnings); + + return newElement; +} + +function setupEventDelegation() { + // Delegate game clicks on parent containers + const gameContainers = [domCache.games, domCache.topGames, domCache.starredGames]; + + gameContainers.forEach(container => { + container.addEventListener("click", (e) => { + const gameElement = e.target.closest("game"); + if (!gameElement) return; + + const clickedStar = e.target.id === "star" || e.target.classList.contains("star"); + + if (clickedStar) { + e.preventDefault(); + e.stopPropagation(); + handleStarClick(gameElement); + } else { + const name = gameElement.getAttribute("data-name"); + const dir = gameElement.getAttribute("data-target"); + const img = gameElement.getAttribute("data-image"); + location.href = `/loader.html?title=${encodeURIComponent(name)}&dir=${dir}&img=${img}&type=g`; + } + }); + }); +} + +function handleStarClick(gameElement) { + const game = gameElement.getAttribute("data-target"); + const starImages = document.querySelectorAll(`game[data-target='${game}'] #star`); + + starredGames = JSON.parse(localStorage.getItem("selenite.starred") || '[]'); + + if (!starredGames.includes(game)) { + starredGames.push(game); + starredGames.sort(); + starImages.forEach(img => img.src = "/img/star-fill.svg"); + } else { + starredGames.splice(starredGames.indexOf(game), 1); + starImages.forEach(img => img.src = "/img/star.svg"); + } + + localStorage.setItem("selenite.starred", JSON.stringify(starredGames)); + renderStarredGames(); +} + +function renderStarredGames() { + domCache.starredHeader.style.display = starredGames.length > 0 ? "block" : "none"; + domCache.starredGames.innerHTML = ""; + + if (starredGames.length === 0) return; + + const fragment = document.createDocumentFragment(); + + starredGames.forEach((gameDir) => { + const originalElement = domCache.games.querySelector(`game[data-target='${gameDir}']`); + if (originalElement) { + const clonedElement = originalElement.cloneNode(true); + fragment.appendChild(clonedElement); + } + }); + + domCache.starredGames.appendChild(fragment); +} + +// Search functionality +document.addEventListener("DOMContentLoaded", () => { + const gameSearch = document.getElementById("gamesearch"); + if (!gameSearch) return; + + gameSearch.addEventListener("input", () => { + const input = gameSearch.value.toUpperCase(); + let hiddenCount = 0; + + if (elements.length > 0) { + elements.forEach((element) => { + const title = element.getAttribute("data-name").toUpperCase(); + if (title.includes(input)) { + element.style.display = "flex"; + } else { + element.style.display = "none"; + hiddenCount++; + } + }); + } + + const noResults = document.getElementById("noResults"); + if (noResults) { + noResults.style.display = hiddenCount >= elements.length ? "flex" : "none"; + } + }); +}); diff --git a/projects.html b/projects.html index 2296ba2..33cc6af 100755 --- a/projects.html +++ b/projects.html @@ -7,10 +7,7 @@ - - - diff --git a/projects_opt.html b/projects_opt.html new file mode 100755 index 0000000..23f4145 --- /dev/null +++ b/projects_opt.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + Projects | Selenite + + + + + + + + + + +

xx games loaded..

+

starred games

+
+

top games

+
+

all games

+
+

games loading..

+

nothing was found! try a new search query.

+
+ + diff --git a/settings.html b/settings.html index 35dcfad..99268f6 100755 --- a/settings.html +++ b/settings.html @@ -142,21 +142,37 @@ } } function downloadData() { - // grab localstorage - // grab cookies - // json.stringify - // base64 - alert("not completed"); + let storage = JSON.stringify(localStorage); + let cookies = document.cookie; + let data = btoa(JSON.stringify({localStorage: storage, cookies: cookies})); + + let file = new Blob([data], {type: "text"}); + let a = document.createElement("a"); + a.href = URL.createObjectURL(file); + a.download = "selenite.dat"; + a.click(); } function uploadData() { - if(prompt("Are you sure you want to upload data?\nThis may overwrite any previous data you had stored.\n\nType \"i am sure\" to continue.") == "i am sure") { - // prompt file upload - // read file - // atob - // set cookies - // set localstorage - alert("not completed"); - } + let input = document.createElement("input"); + input.type = "file"; + input.accept = "dat"; + input.click(); + input.addEventListener("change", e => { + if(prompt("Are you sure you want to upload data?\nThis may overwrite any previous data you had stored.\n\nType \"i am sure\" to continue.") == "i am sure") { + let fileReader = new FileReader(); + fileReader.addEventListener("load", e => { + let data = JSON.parse(atob(e.target.result)); + let local = JSON.parse(data["localStorage"]); + let cookies = data["cookies"]; + + document.cookie = cookies; + Object.keys(local).forEach(e => { + localStorage.setItem(e, local[e]); + }) + }); + fileReader.readAsText(e.target.files[0]); + } + }) } async function deleteAllCaches() { try { @@ -164,7 +180,6 @@ await Promise.all( cacheNames.map(cacheName => { - console.log(`Deleting cache: ${cacheName}`); return caches.delete(cacheName); }) ); @@ -220,9 +235,8 @@

manage data

-

download & upload currently unfinished, use the cloud backups

- - + +
diff --git a/sw.js b/sw.js index 78d7edd..c281380 100644 --- a/sw.js +++ b/sw.js @@ -6,41 +6,41 @@ if(workbox) { self.skipWaiting(); workbox.core.clientsClaim(); - workbox.routing.registerRoute( - /\.(?:png|gif|jpg|jpeg|svg|webp|avif|gif)$/, - new workbox.strategies.CacheFirst({ - cacheName: 'images-cache', - plugins: [ - new workbox.expiration.ExpirationPlugin({ - maxEntries: 600, - maxAgeSeconds: 365 * 24 * 60 * 60, - }), - ], - }) - ); - workbox.routing.registerRoute( - /.*resources\/(semag|sppa).*/, - new workbox.strategies.CacheFirst({ - cacheName: 'resources-cache', - plugins: [ - new workbox.expiration.ExpirationPlugin({ - maxEntries: 100, - maxAgeSeconds: 365 * 24 * 60 * 60, - }), - ], - }) - ); + // workbox.routing.registerRoute( + // /\.(?:png|gif|jpg|jpeg|svg|webp|avif|gif)$/, + // new workbox.strategies.CacheFirst({ + // cacheName: 'images-cache', + // plugins: [ + // new workbox.expiration.ExpirationPlugin({ + // maxEntries: 600, + // maxAgeSeconds: 365 * 24 * 60 * 60, + // }), + // ], + // }) + // ); + // workbox.routing.registerRoute( + // /.*resources\/(semag|sppa).*/, + // new workbox.strategies.CacheFirst({ + // cacheName: 'resources-cache', + // plugins: [ + // new workbox.expiration.ExpirationPlugin({ + // maxEntries: 100, + // maxAgeSeconds: 365 * 24 * 60 * 60, + // }), + // ], + // }) + // ); - workbox.routing.registerRoute( - /.*resources\/(games|apps)\.json$/, - new workbox.strategies.StaleWhileRevalidate({ - cacheName: 'json-cache', - plugins: [ - new workbox.expiration.ExpirationPlugin({ - maxAgeSeconds: 3 * 60 * 60, - maxEntries: 2, - }), - ], - }) - ); + // workbox.routing.registerRoute( + // /.*resources\/(games|apps)\.json$/, + // new workbox.strategies.StaleWhileRevalidate({ + // cacheName: 'json-cache', + // plugins: [ + // new workbox.expiration.ExpirationPlugin({ + // maxAgeSeconds: 3 * 60 * 60, + // maxEntries: 2, + // }), + // ], + // }) + // ); }; \ No newline at end of file