mobile support and shit

This commit is contained in:
sky
2025-11-14 21:53:45 -05:00
parent 896b2a0133
commit 7596d7283d
10 changed files with 436 additions and 74 deletions

View File

@ -113,3 +113,13 @@ body[fast] game {
background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%); background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%);
backdrop-filter: blur(0); backdrop-filter: blur(0);
} }
@media screen and (max-width: 900px) {
game {
width: 40vw;
}
}
@media screen and (max-width: 660px) {
game {
width: 60vw;
}
}

View File

@ -58,3 +58,15 @@ body[fast] #gamecontainer {
background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%); background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%);
backdrop-filter: blur(0); 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;
}
}

View File

@ -1,5 +1,6 @@
body { html,body {
overflow: hidden; overflow: hidden;
height: 100%;
} }
sidebar { sidebar {
background-color: linear-gradient(19deg,rgba(87, 199, 133, 1) 0%, rgba(237, 221, 83, 1) 100%);; background-color: linear-gradient(19deg,rgba(87, 199, 133, 1) 0%, rgba(237, 221, 83, 1) 100%);;
@ -29,13 +30,10 @@ iframe {
} }
.sidebar-divider { .sidebar-divider {
height: 2px;
border-radius: 20px;
width: 80%;
background-color: #ffffff22; background-color: #ffffff22;
/* auto is being stupid /* 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) */ 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 { .sidebar-item-descriptor {
@ -145,3 +143,39 @@ alert p {
top: -50px; 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;
}
}

View File

@ -57,3 +57,13 @@ body[fast] .users {
background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%); background-color: color-mix(in srgb, var(--color-2) 70%, #000000 30%);
backdrop-filter: blur(0); backdrop-filter: blur(0);
} }
@media screen and (max-width: 900px) {
.users {
width: 40vw;
}
}
@media screen and (max-width: 660px) {
.users {
width: 80vw;
}
}

View File

@ -10,7 +10,6 @@
<meta content="/favicon.png" property="og:image" /> <meta content="/favicon.png" property="og:image" />
<meta content="#c77dff" data-react-helmet="true" name="theme-color" /> <meta content="#c77dff" data-react-helmet="true" name="theme-color" />
<meta name="googlebot" content="index, follow, snippet" /> <meta name="googlebot" content="index, follow, snippet" />
<link rel="canonical" href="https://selenite.cc/" />
<meta property="og:description" content="Selenite is the best educational website. With over 400 experiences and an account system, no other websites come close to Selenite." /> <meta property="og:description" content="Selenite is the best educational website. With over 400 experiences and an account system, no other websites come close to Selenite." />
<meta property="og:title" content="Selenite"> <meta property="og:title" content="Selenite">
<meta property="og:type" content="website"> <meta property="og:type" content="website">
@ -41,16 +40,6 @@
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<!-- seo + other things --> <!-- seo + other things -->
<style>
@media screen and (max-width: 660px) {
iframe, sidebar {
display: none;
}
mobile-warning {
display: flex;
}
}
</style>
<title>Selenite</title> <title>Selenite</title>
<link rel="icon" href="/favicon.ico" id="favicon" /> <link rel="icon" href="/favicon.ico" id="favicon" />
<!-- <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563" crossorigin="anonymous"></script> --> <!-- <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563" crossorigin="anonymous"></script> -->
@ -240,7 +229,10 @@
location.href = "https://google.com"; location.href = "https://google.com";
window.close(); 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", ()=>{ document.getElementById("open-bottom-menu").addEventListener("click", ()=>{
@ -266,6 +258,7 @@
<div class="sidebar-item"><a href="#" target="/apps"><img src="/img/apps.svg" /></a><div class="sidebar-item-descriptor">apps</div></div> <!-- apps --> <div class="sidebar-item"><a href="#" target="/apps"><img src="/img/apps.svg" /></a><div class="sidebar-item-descriptor">apps</div></div> <!-- apps -->
<div class="sidebar-item"><a href="#" target="/bookmarklets"><img src="/img/bookmarklets.svg" /></a><div class="sidebar-item-descriptor">bookmarklets</div></div> <!-- reload --> <div class="sidebar-item"><a href="#" target="/bookmarklets"><img src="/img/bookmarklets.svg" /></a><div class="sidebar-item-descriptor">bookmarklets</div></div> <!-- reload -->
<div class="sidebar-item"><a href="#" id="openblank"><img src="/img/open.svg" /></a><div class="sidebar-item-descriptor">open blank</div></div> <!-- open blank --> <div class="sidebar-item"><a href="#" id="openblank"><img src="/img/open.svg" /></a><div class="sidebar-item-descriptor">open blank</div></div> <!-- open blank -->
<div class="sidebar-item"><a href="#" id="fullscreen"><img src="/img/fullscreen.svg" /></a><div class="sidebar-item-descriptor">fullscreen</div></div> <!-- open blank -->
<div class="sidebar-divider"></div> <div class="sidebar-divider"></div>
<div class="sidebar-item"><a href="#" target="/u/"><img src="/img/user.svg" /></a><div class="sidebar-item-descriptor">user profile</div></div> <!-- user --> <div class="sidebar-item"><a href="#" target="/u/"><img src="/img/user.svg" /></a><div class="sidebar-item-descriptor">user profile</div></div> <!-- user -->
<div class="sidebar-item"><a href="#" target="/settings"><img src="/img/settings.svg" /></a><div class="sidebar-item-descriptor">settings</div></div> <!-- settings --> <div class="sidebar-item"><a href="#" target="/settings"><img src="/img/settings.svg" /></a><div class="sidebar-item-descriptor">settings</div></div> <!-- settings -->
@ -279,5 +272,11 @@
<div class="bottom-item"><p>|</p></div> <div class="bottom-item"><p>|</p></div>
<div class="bottom-item"><p id="time">7:41:21 pm</p></div> <div class="bottom-item"><p id="time">7:41:21 pm</p></div>
</div> </div>
<div style="display:none">
<h1 id="edu-title">Johnson Education</h1>
<button id="edu-button">Math Lessons</button>
<p id="edu-text">Educational Resources for Students</p>
<p id="edu-text">Science Textbooks</p>
</div>
</body> </body>
</html> </html>

243
js/games_improved.js Normal file
View File

@ -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";
}
});
});

View File

@ -7,10 +7,7 @@
<!-- initialize my stuff --> <!-- initialize my stuff -->
<script src="/js/all.min.js"></script> <script src="/js/all.min.js"></script>
<script src="/js/games.js"></script> <script src="/js/games.js"></script>
<script src="/js/search.js"></script>
<script src="/js/main.js"></script> <script src="/js/main.js"></script>
<script src="/js/themes.js"></script>
<script src="/js/cookie.js"></script>
<link rel="stylesheet" href="/css/main.css" /> <link rel="stylesheet" href="/css/main.css" />

43
projects_opt.html Executable file
View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html class="sl-theme-dark" lang="en">
<head>
<!-- initialize theme vars
https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff -->
<!-- initialize my stuff -->
<script src="/js/all.min.js"></script>
<!-- <script src="/js/games.js"></script> -->
<script src="/js/games_improved.js"></script>
<script src="/js/main.js"></script>
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/pages.css" />
<link rel="stylesheet" href="/css/games.css" />
<!-- seo + other things -->
<title>Projects | Selenite</title>
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- toastify -->
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3415518411898563"
crossorigin="anonymous"></script>
<script></script>
</head>
<body>
<input type="text" class="searchbar" id="gamesearch" placeholder="Type here to search.." />
<p id="gameCount">xx games loaded..</p>
<p id="starredHeader">starred games</p>
<div id="starredgames"></div>
<p id="topHeader" class="title">top games</p>
<div id="topGames"></div>
<p id="allHeader" class="title">all games</p>
<div id="games">
<p id="loadingMsg">games loading..</p>
<p id="noResults">nothing was found! try a new search query.</p>
</div>
</body>
</html>

View File

@ -142,21 +142,37 @@
} }
} }
function downloadData() { function downloadData() {
// grab localstorage let storage = JSON.stringify(localStorage);
// grab cookies let cookies = document.cookie;
// json.stringify let data = btoa(JSON.stringify({localStorage: storage, cookies: cookies}));
// base64
alert("not completed"); 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() { 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") { let input = document.createElement("input");
// prompt file upload input.type = "file";
// read file input.accept = "dat";
// atob input.click();
// set cookies input.addEventListener("change", e => {
// set localstorage 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") {
alert("not completed"); 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() { async function deleteAllCaches() {
try { try {
@ -164,7 +180,6 @@
await Promise.all( await Promise.all(
cacheNames.map(cacheName => { cacheNames.map(cacheName => {
console.log(`Deleting cache: ${cacheName}`);
return caches.delete(cacheName); return caches.delete(cacheName);
}) })
); );
@ -220,9 +235,8 @@
</section> </section>
<section> <section>
<h2>manage data</h2> <h2>manage data</h2>
<p>download & upload currently unfinished, use the cloud backups</p> <button onclick="downloadData()">download</button>
<button id="downloadData">download</button> <button onclick="uploadData()">upload</button>
<button id="uploadData">upload</button>
<button onclick="wipeData()">wipe (erases all game data)</button> <button onclick="wipeData()">wipe (erases all game data)</button>
<button onclick="deleteAllCaches()">wipe all cache</button> <button onclick="deleteAllCaches()">wipe all cache</button>
</section> </section>

72
sw.js
View File

@ -6,41 +6,41 @@ if(workbox) {
self.skipWaiting(); self.skipWaiting();
workbox.core.clientsClaim(); workbox.core.clientsClaim();
workbox.routing.registerRoute( // workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg|svg|webp|avif|gif)$/, // /\.(?:png|gif|jpg|jpeg|svg|webp|avif|gif)$/,
new workbox.strategies.CacheFirst({ // new workbox.strategies.CacheFirst({
cacheName: 'images-cache', // cacheName: 'images-cache',
plugins: [ // plugins: [
new workbox.expiration.ExpirationPlugin({ // new workbox.expiration.ExpirationPlugin({
maxEntries: 600, // maxEntries: 600,
maxAgeSeconds: 365 * 24 * 60 * 60, // maxAgeSeconds: 365 * 24 * 60 * 60,
}), // }),
], // ],
}) // })
); // );
workbox.routing.registerRoute( // workbox.routing.registerRoute(
/.*resources\/(semag|sppa).*/, // /.*resources\/(semag|sppa).*/,
new workbox.strategies.CacheFirst({ // new workbox.strategies.CacheFirst({
cacheName: 'resources-cache', // cacheName: 'resources-cache',
plugins: [ // plugins: [
new workbox.expiration.ExpirationPlugin({ // new workbox.expiration.ExpirationPlugin({
maxEntries: 100, // maxEntries: 100,
maxAgeSeconds: 365 * 24 * 60 * 60, // maxAgeSeconds: 365 * 24 * 60 * 60,
}), // }),
], // ],
}) // })
); // );
workbox.routing.registerRoute( // workbox.routing.registerRoute(
/.*resources\/(games|apps)\.json$/, // /.*resources\/(games|apps)\.json$/,
new workbox.strategies.StaleWhileRevalidate({ // new workbox.strategies.StaleWhileRevalidate({
cacheName: 'json-cache', // cacheName: 'json-cache',
plugins: [ // plugins: [
new workbox.expiration.ExpirationPlugin({ // new workbox.expiration.ExpirationPlugin({
maxAgeSeconds: 3 * 60 * 60, // maxAgeSeconds: 3 * 60 * 60,
maxEntries: 2, // maxEntries: 2,
}), // }),
], // ],
}) // })
); // );
}; };