1
0
mirror of https://github.com/zumbiepig/MineXLauncher.git synced 2025-06-08 09:24:48 +00:00
This commit is contained in:
zumbiepig 2024-07-25 15:09:32 -07:00
parent 42a2d0ce72
commit 2379faafdc
27 changed files with 216 additions and 205 deletions

View File

@ -5,7 +5,7 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: "npm" - package-ecosystem: 'npm'
directory: "/" directory: '/'
schedule: schedule:
interval: "weekly" interval: 'weekly'

View File

@ -11,7 +11,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version-file: "package.json" node-version-file: 'package.json'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
- name: Lint - name: Lint

View File

@ -6,7 +6,7 @@ on:
workflow_dispatch: workflow_dispatch:
concurrency: concurrency:
group: "gh-pages" group: 'gh-pages'
cancel-in-progress: false cancel-in-progress: false
jobs: jobs:
@ -21,7 +21,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version-file: "package.json" node-version-file: 'package.json'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
- name: Build - name: Build

View File

@ -1,4 +1,5 @@
{ {
"printWidth": 1000, "printWidth": 1000,
"useTabs": true "useTabs": true,
"singleQuote": true
} }

View File

@ -1,12 +1,4 @@
import eslint from "@eslint/js"; import eslint from '@eslint/js';
import tseslint from "typescript-eslint"; import tseslint from 'typescript-eslint';
export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylisticTypeChecked, { export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended);
ignores: ["node_modules"],
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
});

View File

@ -3,7 +3,7 @@
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/resources/styles/default.css" /> <link rel="stylesheet" href="/resources/styles/default.css" />
<script src="/resources/scripts/main.js"></script> <script src="/resources/scripts/main.js" defer></script>
<!-- Google tag (gtag.js) --> <!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-972V2NZ2ZK"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-972V2NZ2ZK"></script>
<script> <script>
@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -19,15 +19,15 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
<style> <style>
body { body {
overflow: hidden; overflow: hidden;
background-color: #1e1e1e; background-color: #1e1e1e;
background-image: url("/resources/images/gifs/loading.gif"); background-image: url('/resources/images/gifs/loading.gif');
background-repeat: no-repeat; background-repeat: no-repeat;
background-attachment: fixed; background-attachment: fixed;
background-position: center; background-position: center;
@ -35,7 +35,7 @@
} }
</style> </style>
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener('DOMContentLoaded', function () {
function isMobile() { function isMobile() {
try { try {
document.exitPointerLock(); document.exitPointerLock();
@ -44,18 +44,18 @@
return true; return true;
} }
} }
const iframe = document.createElement("iframe"); const iframe = document.createElement('iframe');
iframe.id = "embed"; iframe.id = 'embed';
iframe.style.position = "fixed"; iframe.style.position = 'fixed';
iframe.style.top = "0"; iframe.style.top = '0';
iframe.style.left = "0"; iframe.style.left = '0';
iframe.style.width = "100%"; iframe.style.width = '100%';
iframe.style.height = "100%"; iframe.style.height = '100%';
iframe.style.border = "none"; iframe.style.border = 'none';
if (isMobile()) { if (isMobile()) {
iframe.src = "/mobile/"; iframe.src = '/mobile/';
} else { } else {
iframe.src = "/home/game/"; iframe.src = '/home/game/';
} }
document.body.appendChild(iframe); document.body.appendChild(iframe);
}); });

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -12,8 +12,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -12,8 +12,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -1,6 +1,6 @@
body { body {
margin: 0; margin: 0;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #1e1e1e; background-color: #1e1e1e;
color: #fff; color: #fff;
overflow: hidden; overflow: hidden;
@ -188,7 +188,7 @@ nav {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-family: "MinecraftRegular", sans-serif; font-family: 'MinecraftRegular', sans-serif;
font-size: 1em; font-size: 1em;
padding: 7px; padding: 7px;
border: 2px solid #000; border: 2px solid #000;
@ -273,7 +273,7 @@ nav {
} }
.play-button::before { .play-button::before {
content: ""; content: '';
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
@ -441,14 +441,14 @@ nav {
select { select {
width: 100%; width: 100%;
padding: 10px; padding: 10px;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-weight: bold; font-weight: bold;
color: #e0e0e0; color: #e0e0e0;
background-color: #08a74a; background-color: #08a74a;
box-shadow: 4px 4px 0px #2a2a2a, -4px -4px 0px #2a2a2a; box-shadow: 4px 4px 0px #2a2a2a, -4px -4px 0px #2a2a2a;
border-radius: 3px; border-radius: 3px;
appearance: none; appearance: none;
background-image: url("/resources/images/icons/dropdown-selector.png"), linear-gradient(45deg, #0a8338, #086126); background-image: url('/resources/images/icons/dropdown-selector.png'), linear-gradient(45deg, #0a8338, #086126);
background-repeat: no-repeat, repeat; background-repeat: no-repeat, repeat;
background-position: right 10px center, 0 0; background-position: right 10px center, 0 0;
background-size: 15px auto, 100%; background-size: 15px auto, 100%;

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -3,7 +3,7 @@
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/resources/styles/default.css" /> <link rel="stylesheet" href="/resources/styles/default.css" />
<script src="/resources/scripts/main.js"></script> <script src="/resources/scripts/main.js" defer></script>
<!-- Google tag (gtag.js) --> <!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-972V2NZ2ZK"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-972V2NZ2ZK"></script>
<script> <script>
@ -11,8 +11,8 @@
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag("js", new Date()); gtag('js', new Date());
gtag("config", "G-972V2NZ2ZK"); gtag('config', 'G-972V2NZ2ZK');
</script> </script>
<!-- End Google tag --> <!-- End Google tag -->
</head> </head>

View File

@ -1,9 +1,9 @@
import { Router } from "express"; import { Router } from 'express';
const router = Router(); const router = Router();
/* GET home page. */ /* GET home page. */
router.get("/", function (req, res, next) { router.get('/', function (req, res, next) {
res.render("index", { title: "Express" }); res.render('index', { title: 'Express' });
}); });
export default router; export default router;

View File

@ -1,9 +1,9 @@
import { Router } from "express"; import { Router } from 'express';
const router = Router(); const router = Router();
/* GET users listing. */ /* GET users listing. */
router.get("/", function (req, res, next) { router.get('/', function (req, res, next) {
res.send("respond with a resource"); res.send('respond with a resource');
}); });
export default router; export default router;

View File

@ -1,28 +1,28 @@
import createError from "http-errors"; import createError from 'http-errors';
import express, { json, urlencoded, static as serveStatic } from "express"; import express, { json, urlencoded, static as serveStatic } from 'express';
import { join } from "path"; import { join } from 'path';
import cookieParser from "cookie-parser"; import cookieParser from 'cookie-parser';
import logger from "morgan"; import logger from 'morgan';
import debug from "debug"; import debug from 'debug';
import { createServer } from "http"; import { createServer } from 'http';
import indexRouter from "./routes/index.js"; import indexRouter from './routes/index.js';
import usersRouter from "./routes/users.js"; import usersRouter from './routes/users.js';
const __dirname = import.meta.dirname; const __dirname = import.meta.dirname;
const app = express(); const app = express();
app.set("views", join(__dirname, "views")); app.set('views', join(__dirname, 'views'));
app.set("view engine", "pug"); app.set('view engine', 'pug');
app.use(logger("dev")); app.use(logger('dev'));
app.use(json()); app.use(json());
app.use(urlencoded({ extended: false })); app.use(urlencoded({ extended: false }));
app.use(cookieParser()); app.use(cookieParser());
app.use(serveStatic(join(__dirname, "public"))); app.use(serveStatic(join(__dirname, 'public')));
app.use("/", indexRouter); app.use('/', indexRouter);
app.use("/users", usersRouter); app.use('/users', usersRouter);
app.use(function (req, res, next) { app.use(function (req, res, next) {
next(createError(404)); next(createError(404));
@ -30,22 +30,22 @@ app.use(function (req, res, next) {
app.use(function (err, req, res, next) { app.use(function (err, req, res, next) {
res.locals.message = err.message; res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {}; res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500); res.status(err.status || 500);
res.render("error"); res.render('error');
}); });
const debugLogger = debug("minexlauncher:server"); const debugLogger = debug('minexlauncher:server');
const port = normalizePort(process.env.PORT || "3000"); const port = normalizePort(process.env.PORT || '3000');
app.set("port", port); app.set('port', port);
const server = createServer(app); const server = createServer(app);
server.listen(port); server.listen(port);
server.on("error", onError); server.on('error', onError);
server.on("listening", onListening); server.on('listening', onListening);
function normalizePort(val) { function normalizePort(val) {
const port = parseInt(val, 10); const port = parseInt(val, 10);
@ -59,17 +59,17 @@ function normalizePort(val) {
} }
function onError(error) { function onError(error) {
if (error.syscall !== "listen") { if (error.syscall !== 'listen') {
throw error; throw error;
} }
const bind = typeof port === "string" ? "Pipe " + port : "Port " + port; const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
switch (error.code) { switch (error.code) {
case "EACCES": case 'EACCES':
console.error(bind + " requires elevated privileges"); console.error(bind + ' requires elevated privileges');
process.exit(1); process.exit(1);
break; break;
case "EADDRINUSE": case 'EADDRINUSE':
console.error(bind + " is already in use"); console.error(bind + ' is already in use');
process.exit(1); process.exit(1);
break; break;
default: default:
@ -79,6 +79,6 @@ function onError(error) {
function onListening() { function onListening() {
const addr = server.address(); const addr = server.address();
const bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port; const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
debugLogger("Listening on " + bind); debugLogger('Listening on ' + bind);
} }

View File

@ -1,52 +1,44 @@
let selectedVersion = ""; const theme = {
load() {
document.addEventListener("DOMContentLoaded", function () { const setTheme = cookie.get('minexlauncher.theme');
const usernameForm = document.getElementById("username-form") as HTMLFormElement; if (setTheme === null) {
const usernameInput = document.getElementById("username-input") as HTMLInputElement; theme.set('default');
const profileName = document.getElementById("profile-name"); } else if (setTheme !== 'default') {
const link = document.createElement('link');
const savedUsername = cookie.get("launcher_username"); link.rel = 'stylesheet';
if (profileName && savedUsername) { link.href = '/resources/styles/' + setTheme + '.css';
profileName.textContent = savedUsername; document.head.appendChild(link);
} else if (profileName && !savedUsername) {
profileName.textContent = "Default";
} }
},
if (profileName && window.location.pathname === "/settings/") { set(setTheme: string) {
usernameForm.addEventListener("submit", function (event) { cookie.set('minexlauncher.theme', setTheme, 30);
event.preventDefault(); window.location.reload();
const username = usernameInput.value.trim(); },
if (username) { };
profileName.textContent = username;
cookie.set("launcher_username", username, 30);
}
});
}
});
const versionSelector = { const versionSelector = {
open() { open() {
const customOptions = document.querySelector(".custom-options"); const customOptions = document.querySelector('.custom-options');
const customSelect = document.querySelector(".custom-select"); const customSelect = document.querySelector('.custom-select');
if (customOptions && customSelect) { if (customOptions && customSelect) {
customOptions.classList.add("open"); customOptions.classList.add('open');
customSelect.classList.add("open"); customSelect.classList.add('open');
} }
}, },
close() { close() {
const customOptions = document.querySelector(".custom-options"); const customOptions = document.querySelector('.custom-options');
const customSelect = document.querySelector(".custom-select"); const customSelect = document.querySelector('.custom-select');
if (customOptions && customSelect) { if (customOptions && customSelect) {
customOptions.classList.remove("open"); customOptions.classList.remove('open');
customSelect.classList.remove("open"); customSelect.classList.remove('open');
} }
}, },
toggle() { toggle() {
const customOptions = document.querySelector(".custom-options"); const customOptions = document.querySelector('.custom-options');
const customSelect = document.querySelector(".custom-select"); const customSelect = document.querySelector('.custom-select');
if (customOptions && customSelect) { if (customOptions && customSelect) {
customOptions.classList.toggle("open"); customOptions.classList.toggle('open');
customSelect.classList.toggle("open"); customSelect.classList.toggle('open');
} }
}, },
}; };
@ -55,20 +47,20 @@ const game = {
play(version?: string) { play(version?: string) {
if (version) { if (version) {
embed.remove(); embed.remove();
// @ts-expect-error 1234567890 // @ts-expect-error 123
window.top.location.href = version; window.top.location.href = version;
} else if (selectedVersion) { } else if (selectedVersion) {
embed.remove(); embed.remove();
// @ts-expect-error 1234567890 // @ts-expect-error 123
window.top.location.href = selectedVersion; window.top.location.href = selectedVersion;
} else { } else {
alert("Please select a version to play."); alert('Please select a version to play.');
return; return;
} }
}, },
select(path: string, name: string) { select(path: string, name: string) {
selectedVersion = path; selectedVersion = path;
const selector = document.querySelector(".custom-select"); const selector = document.querySelector('.custom-select');
if (selector?.textContent) { if (selector?.textContent) {
if (name) { if (name) {
selector.textContent = `Selected: ${name}`; selector.textContent = `Selected: ${name}`;
@ -80,13 +72,13 @@ const game = {
}, },
archive(client: string) { archive(client: string) {
const clients: Record<string, string> = { const clients: Record<string, string> = {
"1.8.8": "18-client-version", '1.8.8': '18-client-version',
"1.5.2": "15-client-version", '1.5.2': '15-client-version',
"b1.3": "b13-client-version", 'b1.3': 'b13-client-version',
}; };
const dropdown = clients[client] ? (document.getElementById(clients[client]) as HTMLSelectElement) : null; const dropdown = clients[client] ? (document.getElementById(clients[client]) as HTMLSelectElement) : null;
if (dropdown?.value) { if (dropdown?.value) {
selectedVersion = `https://archive.eaglercraft.rip/Eaglercraft${client === "b1.3" ? "_b1.3" : `_${client}`}/client/${dropdown.value}/index.html`; selectedVersion = `https://archive.eaglercraft.rip/Eaglercraft${client === 'b1.3' ? '_b1.3' : `_${client}`}/client/${dropdown.value}/index.html`;
game.play(); game.play();
} }
}, },
@ -94,23 +86,23 @@ const game = {
const embed = { const embed = {
create() { create() {
const iframe = document.createElement("iframe"); const iframe = document.createElement('iframe');
iframe.id = "embed"; iframe.id = 'embed';
iframe.style.position = "fixed"; iframe.style.position = 'fixed';
iframe.style.top = "0"; iframe.style.top = '0';
iframe.style.left = "0"; iframe.style.left = '0';
iframe.style.width = "100%"; iframe.style.width = '100%';
iframe.style.height = "100%"; iframe.style.height = '100%';
iframe.style.border = "none"; iframe.style.border = 'none';
if (isMobile()) { if (isMobile()) {
iframe.src = "/mobile/"; iframe.src = '/mobile/';
} else { } else {
iframe.src = "/home/"; iframe.src = '/home/';
} }
document.body.appendChild(iframe); document.body.appendChild(iframe);
}, },
remove() { remove() {
const iframe = document.getElementById("embed"); const iframe = document.getElementById('embed');
iframe?.remove(); iframe?.remove();
}, },
}; };
@ -118,62 +110,64 @@ const embed = {
const navigate = { const navigate = {
home: { home: {
game() { game() {
window.location.href = "/home/game/"; window.location.href = '/home/game/';
}, },
clients() { clients() {
window.location.href = "/home/clients/"; window.location.href = '/home/clients/';
}, },
archive() { archive() {
window.location.href = "/home/archive/"; window.location.href = '/home/archive/';
}, },
downloads() { downloads() {
window.location.href = "/home/downloads/"; window.location.href = '/home/downloads/';
}, },
}, },
mods: { mods: {
client() { client() {
window.location.href = "/mods/client/"; window.location.href = '/mods/client/';
}, },
mods() { mods() {
window.location.href = "/mods/mods/"; window.location.href = '/mods/mods/';
}, },
resourcepacks() { resourcepacks() {
window.location.href = "/mods/resourcepacks/"; window.location.href = '/mods/resourcepacks/';
}, },
}, },
mobile() { mobile() {
window.location.href = "/mobile/"; window.location.href = '/mobile/';
}, },
updates() { updates() {
window.location.href = "/updates/"; window.location.href = '/updates/';
}, },
servers() { servers() {
window.location.href = "/servers/"; window.location.href = '/servers/';
}, },
settings() { settings() {
window.location.href = "/settings/"; window.location.href = '/settings/';
}, },
}; };
const cookie = { const cookie = {
get(name: string): string | null { get(key: string): string | null {
const cookieArr = document.cookie.split(";"); for (const cookie of document.cookie.replaceAll('; ', ';').split(';')) {
for (const cookie of cookieArr) { const cookiePair = cookie.split('=');
const cookiePair = cookie.split("="); if (encodeURIComponent(key) === cookiePair[0]) {
if (name === cookiePair[0]?.trim()) { return decodeURIComponent(cookiePair[1]);
return decodeURIComponent(cookiePair[1] ?? "");
} }
} }
return null; return null;
}, },
set(name: string, value: string, days: number) { set(key: string, value: string, days: number) {
let expires = ""; let maxAge;
if (days) { if (days) {
const date = new Date(); maxAge = days * 60 * 60 * 24;
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); } else {
expires = "; expires=" + date.toUTCString(); maxAge = 31536000;
} }
document.cookie = name + "=" + (value || "") + expires + "; path=/; domain=" + window.location.hostname.replace(/^www\./, ""); document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}; max-age=${maxAge}; path=/; secure`;
},
delete(key: string) {
document.cookie = `${encodeURIComponent(key)}=; max-age=0; path=/`;
}, },
}; };
@ -193,10 +187,34 @@ function isMobile(): boolean {
} }
} }
if (window.location.hostname === "0.0.0.0") { if (window.location.hostname === '0.0.0.0') {
versionSelector;
game;
navigate; navigate;
query; query;
isMobile;
} }
let selectedVersion: string;
theme.load();
document.addEventListener('DOMContentLoaded', function () {
const usernameForm = document.getElementById('username-form') as HTMLFormElement;
const usernameInput = document.getElementById('username-input') as HTMLInputElement;
const profileName = document.getElementById('profile-name');
const savedUsername = cookie.get('minexlauncher.username');
if (profileName && savedUsername) {
profileName.textContent = savedUsername;
} else if (profileName && !savedUsername) {
profileName.textContent = 'Default';
}
if (profileName && window.location.pathname === '/settings/') {
usernameForm.addEventListener('submit', function (event) {
event.preventDefault();
const username = usernameInput.value.trim();
if (username) {
cookie.set('minexlauncher.username', username, 30);
profileName.textContent = cookie.get('minexlauncher.username');
}
});
}
});

View File

@ -1,22 +1,22 @@
document.addEventListener("DOMContentLoaded", function () { document.addEventListener('DOMContentLoaded', function () {
fetch("/resources/data/mods.json") fetch('/resources/data/mods.json')
.then((response) => response.json()) .then((response) => response.json())
.then((data: { mods: { [x: string]: string; icon: string; author: string; description: string }[] }) => { .then((data: { mods: { [x: string]: string; icon: string; author: string; description: string }[] }) => {
const modListElement = document.querySelector(".mod-list"); const modListElement = document.querySelector('.mod-list');
data.mods.forEach((mod: { [x: string]: string; icon: string; author: string; description: string }) => { data.mods.forEach((mod: { [x: string]: string; icon: string; author: string; description: string }) => {
const modItem = document.createElement("div"); const modItem = document.createElement('div');
modItem.classList.add("mod-item"); modItem.classList.add('mod-item');
modItem.innerHTML = ` modItem.innerHTML = `
<div class="mod-icon"> <div class="mod-icon">
<img src="${mod.icon}" /> <img src="${mod.icon}" />
</div> </div>
<div class="mod-details"> <div class="mod-details">
<h3 class="mod-name">${mod["display-name"] ?? ""}</h3> <h3 class="mod-name">${mod['display-name'] ?? ''}</h3>
<p class="mod-author">By <a href="${mod["author-link"] ?? ""}" target="_blank">${mod.author}</a></p> <p class="mod-author">By <a href="${mod['author-link'] ?? ''}" target="_blank">${mod.author}</a></p>
<p class="mod-description">${mod.description}</p> <p class="mod-description">${mod.description}</p>
<div class="mod-links"> <div class="mod-links">
<a href="${mod["repo-link"] ?? ""}" class="mod-link" target="_blank">Repository</a> <a href="${mod['repo-link'] ?? ''}" class="mod-link" target="_blank">Repository</a>
<a href="${mod["download-link"] ?? ""}" class="mod-link" download>Download</a> <a href="${mod['download-link'] ?? ''}" class="mod-link" download>Download</a>
</div> </div>
</div> </div>
`; `;
@ -24,6 +24,6 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
}) })
.catch((error: unknown) => { .catch((error: unknown) => {
console.error("Error fetching mods:", error); console.error('Error fetching mods:', error);
}); });
}); });

View File

@ -1,22 +1,22 @@
document.addEventListener("DOMContentLoaded", function () { document.addEventListener('DOMContentLoaded', function () {
fetch("/resources/data/mods.json") fetch('/resources/data/mods.json')
.then((response) => response.json()) .then((response) => response.json())
.then((data: { resourcepacks: { [x: string]: string; icon: string; author: string; description: string }[] }) => { .then((data: { resourcepacks: { [x: string]: string; icon: string; author: string; description: string }[] }) => {
const modListElement = document.querySelector(".mod-list"); const modListElement = document.querySelector('.mod-list');
data.resourcepacks.forEach((mod: { [x: string]: string; icon: string; author: string; description: string }) => { data.resourcepacks.forEach((mod: { [x: string]: string; icon: string; author: string; description: string }) => {
const modItem = document.createElement("div"); const modItem = document.createElement('div');
modItem.classList.add("mod-item"); modItem.classList.add('mod-item');
modItem.innerHTML = ` modItem.innerHTML = `
<div class="mod-icon"> <div class="mod-icon">
<img src="${mod.icon}" /> <img src="${mod.icon}" />
</div> </div>
<div class="mod-details"> <div class="mod-details">
<h3 class="mod-name">${mod["display-name"] ?? ""}</h3> <h3 class="mod-name">${mod['display-name'] ?? ''}</h3>
<p class="mod-author">By <a href="${mod["author-link"] ?? ""}" target="_blank">${mod.author}</a></p> <p class="mod-author">By <a href="${mod['author-link'] ?? ''}" target="_blank">${mod.author}</a></p>
<p class="mod-description">${mod.description}</p> <p class="mod-description">${mod.description}</p>
<div class="mod-links"> <div class="mod-links">
<a href="${mod["repo-link"] ?? ""}" class="mod-link" target="_blank">Repository</a> <a href="${mod['repo-link'] ?? ''}" class="mod-link" target="_blank">Repository</a>
<a href="${mod["download-link"] ?? ""}" class="mod-link" download>Download</a> <a href="${mod['download-link'] ?? ''}" class="mod-link" download>Download</a>
</div> </div>
</div> </div>
`; `;
@ -24,6 +24,6 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
}) })
.catch((error: unknown) => { .catch((error: unknown) => {
console.error("Error fetching resource packs:", error); console.error('Error fetching resource packs:', error);
}); });
}); });

View File

@ -1,5 +1,5 @@
{ {
"extends": ["@tsconfig/node20/tsconfig", "@tsconfig/strictest/tsconfig"], "extends": ["@tsconfig/node20/tsconfig"],
"compilerOptions": { "compilerOptions": {
"moduleResolution": "bundler", "moduleResolution": "bundler",
"module": "preserve", "module": "preserve",