Compare commits
No commits in common. "main" and "main" have entirely different histories.
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
The following versions of this project that are currently supported and unsupported:
|
The following versions of this project that are currently supported and unsupported:
|
||||||
|
|
||||||
- **Version 2.3.7** – Supported ✅
|
|
||||||
- **Version 2.3.5** – Supported ✅
|
- **Version 2.3.5** – Supported ✅
|
||||||
- **Version 2.3.1** – Supported ✅
|
- **Version 2.3.1** – Supported ✅
|
||||||
- **Version 2.3.0** – Supported ✅
|
- **Version 2.3.0** – Supported ✅
|
||||||
|
@ -18,4 +17,4 @@ The following versions of this project that are currently supported and unsuppor
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
If you are experiencing an issue with Waves unrelated to security, feel free to join our [Discord Server](https://discord.gg/dJvdkPRheV) and open a ticket.
|
If you are experiencing an issue with Waves unrelated to security, feel free to join our [Discord](https://discord.gg/dJvdkPRheV) server and open a ticket.
|
||||||
|
|
257
index.mjs
257
index.mjs
|
@ -1,126 +1,74 @@
|
||||||
import cluster from "cluster";
|
import cluster from "cluster";
|
||||||
import os from "os";
|
import os from "os";
|
||||||
import net from "net";
|
import net from "net";
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import { spawnSync } from "child_process";
|
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { createServer } from "http";
|
import { createServer } from "http";
|
||||||
|
import path from "path";
|
||||||
import compression from "compression";
|
import compression from "compression";
|
||||||
import WebSocket from "ws";
|
import WebSocket from "ws";
|
||||||
import { LRUCache } from "lru-cache";
|
|
||||||
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
|
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
|
||||||
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
|
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
|
||||||
import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
|
import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
|
||||||
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
|
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
|
||||||
import wisp from "wisp-server-node";
|
import wisp from "wisp-server-node";
|
||||||
|
import NodeCache from "node-cache";
|
||||||
const surgeConfigPath = path.resolve("surge.config.json");
|
|
||||||
const isSurgedRun = process.argv.includes("--surged");
|
|
||||||
let startTime = Date.now();
|
|
||||||
|
|
||||||
function applySurgeAndRestartIfNeeded() {
|
|
||||||
if (isSurgedRun) {
|
|
||||||
try {
|
|
||||||
const config = JSON.parse(fs.readFileSync(surgeConfigPath, "utf-8"));
|
|
||||||
process.env.UV_THREADPOOL_SIZE = String(config.uvThreadpoolSize);
|
|
||||||
} catch {}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = spawnSync("node", ["./others/surge.mjs"], { stdio: "inherit" });
|
|
||||||
if (result.error) process.exit(1);
|
|
||||||
|
|
||||||
const config = JSON.parse(fs.readFileSync(surgeConfigPath, "utf-8"));
|
|
||||||
const nodeArgs = [...config.nodeFlags, path.resolve("index.mjs"), "--surged"];
|
|
||||||
const env = {
|
|
||||||
...process.env,
|
|
||||||
UV_THREADPOOL_SIZE: String(config.uvThreadpoolSize),
|
|
||||||
ALREADY_SURGED: "true"
|
|
||||||
};
|
|
||||||
|
|
||||||
const relaunch = spawnSync(process.execPath, nodeArgs, { stdio: "inherit", env });
|
|
||||||
process.exit(relaunch.status || 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
applySurgeAndRestartIfNeeded();
|
|
||||||
|
|
||||||
if (global.gc) {
|
|
||||||
setInterval(() => {
|
|
||||||
const { heapUsed, heapTotal } = process.memoryUsage();
|
|
||||||
if (heapTotal > 0 && heapUsed / heapTotal > 0.7) global.gc();
|
|
||||||
}, 60000);
|
|
||||||
}
|
|
||||||
|
|
||||||
import "./others/scaler.mjs";
|
|
||||||
import "./others/warmup.mjs";
|
|
||||||
|
|
||||||
const cache = new LRUCache({
|
|
||||||
maxSize: 1000,
|
|
||||||
ttl: 60_000,
|
|
||||||
allowStale: false,
|
|
||||||
sizeCalculation: (value, key) => Buffer.byteLength(value) + Buffer.byteLength(key)
|
|
||||||
});
|
|
||||||
|
|
||||||
const port = parseInt(process.env.PORT || "3000", 10);
|
const port = parseInt(process.env.PORT || "3000", 10);
|
||||||
|
cluster.schedulingPolicy = cluster.SCHED_RR;
|
||||||
|
|
||||||
function logInfo(msg) {
|
function logInfo(message) {
|
||||||
console.info(`[~] ${msg}`);
|
console.info(`[INFO] ${message}`);
|
||||||
|
}
|
||||||
|
function logError(error) {
|
||||||
|
const msg = error instanceof Error ? error.message : error;
|
||||||
|
console.error(`[ERR] ${msg}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function logSuccess(msg) {
|
process.on("uncaughtException", (err) => logError(`Unhandled Exception: ${err}`));
|
||||||
console.info(`[+] ${msg}`);
|
process.on("unhandledRejection", (reason) => logError(`Unhandled Promise Rejection: ${reason}`));
|
||||||
}
|
|
||||||
|
|
||||||
function logError(err) {
|
|
||||||
console.error(`[!] ${err instanceof Error ? err.message : err}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.on("uncaughtException", err => logError(`Unhandled Exception: ${err}`));
|
|
||||||
process.on("unhandledRejection", reason => logError(`Unhandled Rejection: ${reason}`));
|
|
||||||
|
|
||||||
if (cluster.isPrimary) {
|
if (cluster.isPrimary) {
|
||||||
const cpus = os.cpus().length;
|
const numCPUs = os.cpus().length;
|
||||||
const workers = Math.max(1, cpus - 1);
|
logInfo(`Master started. Forking ${numCPUs} workers.`);
|
||||||
|
for (let i = 0; i < numCPUs; i++) {
|
||||||
logInfo(`Master: forking ${workers} workers`);
|
|
||||||
|
|
||||||
for (let i = 0; i < workers; i++) {
|
|
||||||
cluster.fork();
|
cluster.fork();
|
||||||
}
|
}
|
||||||
|
cluster.on("exit", (worker, code, signal) => {
|
||||||
cluster.on("exit", worker => {
|
logError(`Worker ${worker.process.pid} terminated (code: ${code}, signal: ${signal}). Restarting...`);
|
||||||
logError(`Worker ${worker.process.pid} exited. Restarting...`);
|
|
||||||
cluster.fork();
|
cluster.fork();
|
||||||
});
|
});
|
||||||
|
let currentWorker = 0;
|
||||||
let current = 0;
|
const server = net.createServer({ pauseOnConnect: true }, (connection) => {
|
||||||
const server = net.createServer({ pauseOnConnect: true }, conn => {
|
const workerIds = Object.keys(cluster.workers);
|
||||||
const workersArr = Object.values(cluster.workers);
|
if (workerIds.length === 0) {
|
||||||
if (!workersArr.length) return conn.destroy();
|
connection.destroy();
|
||||||
const worker = workersArr[current++ % workersArr.length];
|
return;
|
||||||
worker.send("sticky-session:connection", conn);
|
}
|
||||||
|
const worker = cluster.workers[workerIds[currentWorker % workerIds.length]];
|
||||||
|
currentWorker++;
|
||||||
|
if (worker) worker.send("sticky-session:connection", connection);
|
||||||
});
|
});
|
||||||
|
server.on("error", (err) => logError(`Server error: ${err}`));
|
||||||
server.on("error", err => logError(`Server error: ${err}`));
|
server.listen(port, () => logInfo(`Server running at http://localhost:${port}`));
|
||||||
server.listen(port, () => logSuccess(`Server listening on ${port}`));
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
process.env.UV_THREADPOOL_SIZE = os.cpus().length * 2;
|
||||||
|
|
||||||
const __dirname = process.cwd();
|
const __dirname = process.cwd();
|
||||||
const publicPath = path.join(__dirname, "public");
|
const publicPath = path.join(__dirname, "public");
|
||||||
const app = express();
|
const app = express();
|
||||||
let latencySamples = [];
|
|
||||||
|
|
||||||
app.use(compression({ level: 4, memLevel: 4, threshold: 1024 }));
|
app.use(compression({ level: 9, threshold: 128, memLevel: 9 }));
|
||||||
|
|
||||||
|
const cache = new NodeCache({ stdTTL: 1, checkperiod: 1 });
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
const key = req.originalUrl;
|
const key = req.originalUrl;
|
||||||
const val = cache.get(key);
|
if (cache.has(key)) {
|
||||||
if (val) {
|
|
||||||
res.setHeader("X-Cache", "HIT");
|
res.setHeader("X-Cache", "HIT");
|
||||||
return res.send(val);
|
return res.send(cache.get(key));
|
||||||
}
|
}
|
||||||
res.sendResponse = res.send.bind(res);
|
res.sendResponse = res.send;
|
||||||
res.send = body => {
|
res.send = (body) => {
|
||||||
cache.set(key, body);
|
cache.set(key, body);
|
||||||
res.setHeader("X-Cache", "MISS");
|
res.setHeader("X-Cache", "MISS");
|
||||||
res.sendResponse(body);
|
res.sendResponse(body);
|
||||||
|
@ -128,7 +76,7 @@ if (cluster.isPrimary) {
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
const staticOpts = { maxAge: "7d", immutable: true };
|
const staticOpts = { maxAge: "1s" };
|
||||||
app.use("/baremux/", express.static(baremuxPath, staticOpts));
|
app.use("/baremux/", express.static(baremuxPath, staticOpts));
|
||||||
app.use("/epoxy/", express.static(epoxyPath, staticOpts));
|
app.use("/epoxy/", express.static(epoxyPath, staticOpts));
|
||||||
app.use("/libcurl/", express.static(libcurlPath, staticOpts));
|
app.use("/libcurl/", express.static(libcurlPath, staticOpts));
|
||||||
|
@ -136,129 +84,62 @@ if (cluster.isPrimary) {
|
||||||
app.use("/wah/", express.static(uvPath, staticOpts));
|
app.use("/wah/", express.static(uvPath, staticOpts));
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
const sendHtml = file => (_req, res) => res.sendFile(path.join(publicPath, file));
|
app.get("/", (req, res) => res.sendFile(path.join(publicPath, "$.html")));
|
||||||
|
app.get("/g", (req, res) => res.sendFile(path.join(publicPath, "!.html")));
|
||||||
app.get("/", sendHtml("$.html"));
|
app.get("/a", (req, res) => res.sendFile(path.join(publicPath, "!!.html")));
|
||||||
app.get("/g", sendHtml("!.html"));
|
app.get("/ai", (req, res) => res.sendFile(path.join(publicPath, "!!!.html")));
|
||||||
app.get("/s", sendHtml("!!.html"));
|
app.get("/resent", (req, res) => res.sendFile(path.join(publicPath, "resent", "index.html")));
|
||||||
app.get("/resent", (_req, res) => res.sendFile(path.join(publicPath, "resent", "index.html")));
|
app.use((req, res) => res.status(404).sendFile(path.join(publicPath, "404.html")));
|
||||||
|
|
||||||
app.get("/api/info", (_req, res) => {
|
|
||||||
try {
|
|
||||||
const average = latencySamples.length
|
|
||||||
? latencySamples.reduce((a, b) => a + b, 0) / latencySamples.length
|
|
||||||
: 0;
|
|
||||||
let speed = "Medium";
|
|
||||||
if (average < 200) speed = "Fast";
|
|
||||||
else if (average > 500) speed = "Slow";
|
|
||||||
const cpus = os.cpus();
|
|
||||||
const totalMem = os.totalmem() / 1024 / 1024 / 1024;
|
|
||||||
res.json({
|
|
||||||
speed,
|
|
||||||
averageLatency: average.toFixed(2),
|
|
||||||
specs: `${cpus[0].model} + ${cpus.length} CPU Cores + ${totalMem.toFixed(1)}GB of RAM`,
|
|
||||||
startTime,
|
|
||||||
samples: latencySamples.length,
|
|
||||||
timestamp: Date.now()
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
res.status(500).json({ error: "Internal error" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/api/latest-commit", async (_req, res) => {
|
|
||||||
try {
|
|
||||||
const ghRes = await fetch(
|
|
||||||
"https://api.github.com/repos/xojw/waves/commits?per_page=1",
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"User-Agent": "waves-app",
|
|
||||||
Accept: "application/vnd.github.v3+json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (!ghRes.ok) return res.status(ghRes.status).json({ error: "GitHub API error" });
|
|
||||||
|
|
||||||
const commits = await ghRes.json();
|
|
||||||
const updates = commits.map(c => ({
|
|
||||||
sha: c.sha.slice(0, 7),
|
|
||||||
message: c.commit.message.split("\n")[0],
|
|
||||||
author: c.commit.author.name,
|
|
||||||
date: c.commit.author.date
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.json({ repo: "xojw/waves", updates });
|
|
||||||
} catch {
|
|
||||||
res.status(500).json({ error: "Internal server error" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use((_req, res) => res.status(404).sendFile(path.join(publicPath, "404.html")));
|
|
||||||
|
|
||||||
const server = createServer(app);
|
const server = createServer(app);
|
||||||
server.keepAliveTimeout = 0;
|
server.keepAliveTimeout = 0;
|
||||||
server.headersTimeout = 0;
|
server.headersTimeout = 0;
|
||||||
|
|
||||||
const pingWSS = new WebSocket.Server({
|
const pingWSS = new WebSocket.Server({ noServer: true, maxPayload: 1048576 });
|
||||||
noServer: true,
|
|
||||||
maxPayload: 4 * 1024 * 1024,
|
|
||||||
perMessageDeflate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
pingWSS.on("connection", (ws, req) => {
|
pingWSS.on("connection", (ws, req) => {
|
||||||
const remote = req.socket.remoteAddress || "unknown";
|
const remoteAddress = req.socket.remoteAddress || "unknown";
|
||||||
let lat = [];
|
let latencies = [];
|
||||||
const interval = setInterval(() => {
|
const pingInterval = setInterval(() => {
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
if (ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send(JSON.stringify({ type: "ping", timestamp: Date.now() }));
|
const timestamp = Date.now();
|
||||||
|
ws.send(JSON.stringify({ type: "ping", timestamp }));
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
ws.on("message", (message) => {
|
||||||
ws.on("message", msg => {
|
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(msg);
|
const data = JSON.parse(message);
|
||||||
if (data.type === "pong" && data.timestamp) {
|
if (data.type === "pong" && data.timestamp) {
|
||||||
const d = Date.now() - data.timestamp;
|
const latency = Date.now() - data.timestamp;
|
||||||
lat.push(d);
|
latencies.push(latency);
|
||||||
if (lat.length > 5) lat.shift();
|
if (latencies.length > 5) latencies.shift();
|
||||||
latencySamples.push(d);
|
ws.send(JSON.stringify({ type: "latency", latency }));
|
||||||
if (latencySamples.length > 100) latencySamples.shift();
|
|
||||||
ws.send(JSON.stringify({ type: "latency", latency: d }));
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(`Ping error: ${e}`);
|
logError(`Ping error: ${e}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on("close", () => {
|
ws.on("close", () => {
|
||||||
clearInterval(interval);
|
clearInterval(pingInterval);
|
||||||
const avg = lat.length
|
const avgLatency = latencies.length ? latencies.reduce((a, b) => a + b) / latencies.length : 0;
|
||||||
? (lat.reduce((a, b) => a + b) / lat.length).toFixed(2)
|
logInfo(`Conn from ${remoteAddress} closed. Avg: ${avgLatency.toFixed(2)}ms.`);
|
||||||
: 0;
|
|
||||||
logInfo(`WS ${remote} closed. Avg: ${avg}ms`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("upgrade", (req, sock, head) => {
|
server.on("upgrade", (req, socket, head) => {
|
||||||
if (req.url === "/w/ping") {
|
if (req.url === "/w/ping") {
|
||||||
pingWSS.handleUpgrade(req, sock, head, ws =>
|
pingWSS.handleUpgrade(req, socket, head, (ws) => pingWSS.emit("connection", ws, req));
|
||||||
pingWSS.emit("connection", ws, req)
|
|
||||||
);
|
|
||||||
} else if (req.url.startsWith("/w/")) {
|
} else if (req.url.startsWith("/w/")) {
|
||||||
wisp.routeRequest(req, sock, head);
|
wisp.routeRequest(req, socket, head);
|
||||||
} else {
|
} else {
|
||||||
sock.end();
|
socket.end();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
server.on("error", (err) => logError(`Worker server error: ${err}`));
|
||||||
server.on("error", err => logError(`Worker error: ${err}`));
|
server.listen(0, () => logInfo(`Worker ${process.pid} ready.`));
|
||||||
|
process.on("message", (message, connection) => {
|
||||||
server.listen(0, () => logSuccess(`Worker ${process.pid} ready`));
|
if (message === "sticky-session:connection") {
|
||||||
|
server.emit("connection", connection);
|
||||||
process.on("message", (msg, conn) => {
|
connection.resume();
|
||||||
if (msg === "sticky-session:connection" && conn) {
|
|
||||||
server.emit("connection", conn);
|
|
||||||
conn.resume();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -1,36 +0,0 @@
|
||||||
import { LRUCache } from 'lru-cache';
|
|
||||||
|
|
||||||
let maxKeys = 10_000;
|
|
||||||
let cache = makeCache(maxKeys);
|
|
||||||
|
|
||||||
function makeCache(maxEntries) {
|
|
||||||
return new LRUCache({
|
|
||||||
maxSize: maxEntries,
|
|
||||||
ttl: 60_000,
|
|
||||||
allowStale: false,
|
|
||||||
updateAgeOnGet: false,
|
|
||||||
updateAgeOnHas: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function scaleCache() {
|
|
||||||
const { heapUsed, heapTotal } = process.memoryUsage();
|
|
||||||
const freeHeapRatio = (heapTotal - heapUsed) / heapTotal;
|
|
||||||
|
|
||||||
const newMax = freeHeapRatio > 0.5
|
|
||||||
? 20_000
|
|
||||||
: freeHeapRatio < 0.2
|
|
||||||
? 5_000
|
|
||||||
: 10_000;
|
|
||||||
|
|
||||||
if (newMax !== maxKeys) {
|
|
||||||
maxKeys = newMax;
|
|
||||||
cache = makeCache(maxKeys);
|
|
||||||
console.log(`[SCALER] freeHeap ${( (heapTotal - heapUsed)/1e6 ).toFixed(1)}MB → maxKeys: ${maxKeys}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setInterval(scaleCache, 60_000);
|
|
||||||
scaleCache();
|
|
||||||
|
|
||||||
export { cache };
|
|
|
@ -1,57 +0,0 @@
|
||||||
import { execSync } from "child_process";
|
|
||||||
import os from "os";
|
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
const log = (msg) => console.log(`[SURGE] ${msg}`);
|
|
||||||
const surgePath = path.resolve("surge.config.json");
|
|
||||||
|
|
||||||
function generateSurgeFlags() {
|
|
||||||
const cpus = os.cpus().length;
|
|
||||||
const flags = [
|
|
||||||
"--max-old-space-size=4096",
|
|
||||||
"--optimize_for_size",
|
|
||||||
"--gc-global",
|
|
||||||
"--max-semi-space-size=256",
|
|
||||||
"--no-warnings",
|
|
||||||
"--expose-gc"
|
|
||||||
];
|
|
||||||
|
|
||||||
if (process.platform !== "win32") {
|
|
||||||
flags.push("--use-largepages=on");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
uvThreadpoolSize: cpus * 2,
|
|
||||||
nodeFlags: flags
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeSurgeFile(flags) {
|
|
||||||
fs.writeFileSync(surgePath, JSON.stringify(flags, null, 2));
|
|
||||||
log("Surge config saved.");
|
|
||||||
}
|
|
||||||
|
|
||||||
function launchSurgedBackend(flags) {
|
|
||||||
const args = [
|
|
||||||
...flags.nodeFlags,
|
|
||||||
"index.mjs",
|
|
||||||
"--surged"
|
|
||||||
];
|
|
||||||
log(`Launching backend: node ${args.join(" ")}`);
|
|
||||||
execSync(`node ${args.join(" ")}`, { stdio: "inherit" });
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSurgedRun() {
|
|
||||||
return process.argv.includes("--surged");
|
|
||||||
}
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
if (isSurgedRun()) return;
|
|
||||||
|
|
||||||
log("Detecting best settings...");
|
|
||||||
const flags = generateSurgeFlags();
|
|
||||||
writeSurgeFile(flags);
|
|
||||||
launchSurgedBackend(flags);
|
|
||||||
process.exit(0);
|
|
||||||
})();
|
|
|
@ -1,59 +0,0 @@
|
||||||
import http from 'http';
|
|
||||||
|
|
||||||
const endpoints = [
|
|
||||||
'http://localhost:3000/',
|
|
||||||
'http://localhost:3000/g',
|
|
||||||
'http://localhost:3000/a'
|
|
||||||
];
|
|
||||||
|
|
||||||
function httpGet(url, timeout = 5000) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const req = http.get(url, (res) => {
|
|
||||||
res.on('data', () => {});
|
|
||||||
res.on('end', () => {
|
|
||||||
resolve({ url, statusCode: res.statusCode });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
req.on('error', (e) => {
|
|
||||||
resolve({ url, error: e.message });
|
|
||||||
});
|
|
||||||
|
|
||||||
req.setTimeout(timeout, () => {
|
|
||||||
req.abort();
|
|
||||||
resolve({ url, error: 'Timeout' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function warm(retries = 2) {
|
|
||||||
const results = await Promise.all(endpoints.map(async (url) => {
|
|
||||||
for (let i = 0; i <= retries; i++) {
|
|
||||||
const res = await httpGet(url);
|
|
||||||
if (!res.error) {
|
|
||||||
console.log(`[WARMUP] ${url} → ${res.statusCode}`);
|
|
||||||
return res;
|
|
||||||
} else {
|
|
||||||
console.warn(`[WARMUP] ${url} attempt ${i + 1} failed: ${res.error}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { url, error: `Failed after ${retries + 1} attempts` };
|
|
||||||
}));
|
|
||||||
|
|
||||||
const failed = results.filter(r => r.error);
|
|
||||||
if (failed.length) {
|
|
||||||
console.warn(`[WARMUP] Some endpoints failed to warm:`, failed);
|
|
||||||
} else {
|
|
||||||
console.log('[WARMUP] All endpoints warmed successfully');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function periodicWarmup(intervalMs = 5 * 60 * 1000) {
|
|
||||||
while (true) {
|
|
||||||
await warm();
|
|
||||||
console.log('[WARMUP] Cycle done');
|
|
||||||
await new Promise(res => setTimeout(res, intervalMs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => periodicWarmup(), 2000);
|
|
3285
package-lock.json
generated
Normal file
3285
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
81
package.json
81
package.json
|
@ -1,41 +1,44 @@
|
||||||
{
|
{
|
||||||
"name": "waves",
|
"name": "waves",
|
||||||
"version": "2.8.7",
|
"version": "2.3.5",
|
||||||
"description": "A sleek and minimalist Web Proxy.",
|
"description": "A sleek and minimalist Web Proxy.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"npm": ">=7.0.0",
|
"npm": ">=7.0.0",
|
||||||
"node": ">=16.0.0"
|
"node": ">=16.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index.mjs",
|
"start": "node index.mjs",
|
||||||
"dev": "nodemon index.mjs",
|
"dev": "nodemon index.mjs",
|
||||||
"lint": "eslint ."
|
"lint": "eslint ."
|
||||||
},
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"name": "sent",
|
"name": "sent",
|
||||||
"email": "sentttt@proton.me"
|
"email": "sentttt@proton.me"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mercuryworkshop/bare-mux": "latest",
|
"@mercuryworkshop/bare-mux": "latest",
|
||||||
"@mercuryworkshop/epoxy-transport": "latest",
|
"@mercuryworkshop/epoxy-transport": "latest",
|
||||||
"@mercuryworkshop/libcurl-transport": "latest",
|
"@mercuryworkshop/libcurl-transport": "latest",
|
||||||
"@titaniumnetwork-dev/ultraviolet": "latest",
|
"@titaniumnetwork-dev/ultraviolet": "latest",
|
||||||
"axios": "latest",
|
"axios": "^1.8.2",
|
||||||
"cache": "latest",
|
"cache": "^3.0.0",
|
||||||
"compression": "latest",
|
"compression": "latest",
|
||||||
"cors": "latest",
|
"cors": "^2.8.5",
|
||||||
"express": "latest",
|
"express": "latest",
|
||||||
"express-rate-limit": "latest",
|
"express-rate-limit": "^7.5.0",
|
||||||
"lru-cache": "latest",
|
"fs": "^0.0.1-security",
|
||||||
"wisp-server-node": "latest",
|
"node": "^23.9.0",
|
||||||
"ws": "latest"
|
"node-cache": "latest",
|
||||||
},
|
"node-fetch": "latest",
|
||||||
"devDependencies": {
|
"wisp-server-node": "latest",
|
||||||
"eslint": "latest",
|
"ws": "latest"
|
||||||
"glob": "latest",
|
},
|
||||||
"nodemon": "latest",
|
"devDependencies": {
|
||||||
"prettier": "latest",
|
"eslint": "latest",
|
||||||
"rimraf": "latest"
|
"glob": "latest",
|
||||||
}
|
"nodemon": "latest",
|
||||||
|
"prettier": "latest",
|
||||||
|
"rimraf": "latest"
|
||||||
|
}
|
||||||
}
|
}
|
243
public/!!.html
243
public/!!.html
|
@ -1,155 +1,100 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta property="og:title" content="Waves." />
|
<meta property="og:title" content="Waves. - Apps"/>
|
||||||
<meta property="og:description" content="A sleek and minimalist web proxy." />
|
<meta property="og:description" content="A sleek and minimalist web proxy."/>
|
||||||
<meta property="og:image" content="/assets/images/icons/favicon.ico" />
|
<meta property="og:image" content="/assets/images/icons/favicon.ico"/>
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff"/>
|
||||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
<meta name="msapplication-TileColor" content="#ffffff"/>
|
||||||
<title>Waves.</title>
|
<title>Waves.</title>
|
||||||
|
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico">
|
||||||
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
<link rel="stylesheet" href="/assets/css/$.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/settings.css">
|
||||||
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
|
<link rel="stylesheet" href="/assets/css/toast.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/a.css">
|
||||||
<link rel="stylesheet" href="/assets/css/$.css" />
|
<link href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css">
|
||||||
<link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
|
||||||
<link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script><script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-WGJ2192JZY');</script>
|
||||||
<link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script>
|
||||||
<link rel="preload" href="/assets/css/s.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
</head>
|
||||||
<noscript>
|
<body>
|
||||||
<link rel="stylesheet" href="/assets/css/settings.css" />
|
<script src="/baremux/index.js"></script>
|
||||||
<link rel="stylesheet" href="/assets/css/toast.css" />
|
<script src="/wah/uv.bundle.js" defer></script>
|
||||||
<link rel="stylesheet" href="/assets/css/nprogress.css" />
|
<script src="/wah/cute1.js" defer></script>
|
||||||
<link rel="stylesheet" href="/assets/css/s.css" />
|
<script src="/assets/js/navbar.js" defer></script>
|
||||||
</noscript>
|
<script src="/assets/js/load.js" defer></script>
|
||||||
|
<script src="/assets/js/eruda.js" defer></script>
|
||||||
<link rel="preload" as="style" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" onload="this.onload=null;this.rel='stylesheet'" />
|
<script src="/assets/js/register.js" defer></script>
|
||||||
<noscript>
|
<script src="/assets/js/settings.js" defer></script>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
|
<script src="/assets/js/greetings.js" defer></script>
|
||||||
</noscript>
|
<script src="/assets/js/shortcuts.js" defer></script>
|
||||||
|
<script src="/assets/js/$.js" defer></script>
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script>
|
<script src="/assets/js/a.js" defer></script>
|
||||||
<script>
|
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
|
||||||
window.dataLayer = window.dataLayer || [];
|
<div class="absolute inset-0 overflow-hidden">
|
||||||
function gtag() {
|
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
|
||||||
dataLayer.push(arguments);
|
</div>
|
||||||
}
|
|
||||||
gtag("js", new Date());
|
|
||||||
gtag("config", "G-WGJ2192JZY");
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script src="/baremux/index.js" defer></script>
|
|
||||||
<script src="/assets/js/nprogress.js?v=0.2.0" defer></script>
|
|
||||||
<script src="/wah/uv.bundle.js" defer></script>
|
|
||||||
<script src="/wah/cute1.js" defer></script>
|
|
||||||
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
|
|
||||||
<script src="/assets/js/register.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/settings.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/greetings.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/shortcuts.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/$.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/s.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/wv.js?v=1.4.1" defer></script>
|
|
||||||
|
|
||||||
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
|
|
||||||
<div class="absolute inset-0 overflow-hidden">
|
|
||||||
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="home-navbar">
|
||||||
|
<img src="/assets/images/icons/favicon.ico" class="favicon">
|
||||||
<div class="home-navbar">
|
<span id="waves">Waves.</span>
|
||||||
<img src="/assets/images/icons/favicon.ico" class="favicon" alt="favicon" />
|
<a href="/" id="home">Home</a>
|
||||||
<span id="waves">Waves.</span>
|
<a href="/g" id="games">Games</a>
|
||||||
<a href="/" id="home">Home</a>
|
<a href="/a" id="apps">Apps</a>
|
||||||
<a href="/g" id="games">Games</a>
|
<a href="#" id="movies">Movies</a>
|
||||||
<a href="/s" id="shortcuts" style="color: #ffffff;">Shortcuts</a>
|
<a href="#" id="ai">AI</a>
|
||||||
<a href="#" id="movies">Movies</a>
|
<a href="#" id="settings-icon">
|
||||||
<a href="#" id="ai">AI</a>
|
<i class="settings-icon fa-regular fa-gear"></i>
|
||||||
<a href="#" id="settings-icon">
|
</a>
|
||||||
<i class="settings-icon fa-regular fa-gear"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="settings-menu" class="settings-menu"></div>
|
|
||||||
|
|
||||||
<div class="navbar">
|
|
||||||
<ul class="nav-buttons">
|
|
||||||
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
|
|
||||||
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
|
|
||||||
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
|
|
||||||
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
|
|
||||||
<li>
|
|
||||||
<div class="small-searchbar" style="position: relative;">
|
|
||||||
<i id="lockIcon" class="fa-solid fa-lock"></i>
|
|
||||||
<input class="waves" type="text" id="searchInputt" placeholder="Search for a query or enter a URL..." autocomplete="off" style="padding-left: 40px;" />
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
|
|
||||||
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
|
|
||||||
<li><a href="/s"><i class="fa-regular fa-rocket"></i></a></li>
|
|
||||||
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content shortcuts-page">
|
|
||||||
<h1>Shortcuts</h1>
|
|
||||||
<div class="shortcuts-search-bar">
|
|
||||||
<input type="text" id="shortcutSearchInput" placeholder="Search shortcuts..." autocomplete="off" />
|
|
||||||
<span class="shortcut-indicator-4">Ctrl + S</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="shortcuts-grid"></div>
|
<div id="settings-menu" class="settings-menu"></div>
|
||||||
</div>
|
<div class="navbar">
|
||||||
|
<ul class="nav-buttons">
|
||||||
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
|
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
|
||||||
<div id="overlay" class="overlay"></div>
|
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
|
||||||
|
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
|
||||||
<div id="namePrompt" class="popup">
|
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
|
||||||
<div class="input-container">
|
<li>
|
||||||
<label for="userName">Please enter a name so we know what to call you:</label>
|
<div class="small-searchbar" style="position: relative;">
|
||||||
<div class="input-wrapper">
|
<i id="lockIcon" class="fa-solid fa-lock"></i>
|
||||||
<input type="text" id="userName" placeholder="Your name" autocomplete="off" />
|
<input class="waves" type="text" id="searchInputt"
|
||||||
</div>
|
placeholder="Search for a query or enter a URL..." autocomplete="off"
|
||||||
<button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
|
style="padding-left: 40px;">
|
||||||
|
<span class="shortcut-indicator-2">Ctrl + S</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
|
||||||
|
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
|
||||||
|
<li><a href="/a"><i class="fa-regular fa-grid-2"></i></a></li>
|
||||||
|
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="content apps-page">
|
||||||
|
<h1>Apps</h1>
|
||||||
<iframe id="cool-iframe" class="iframe"></iframe>
|
<div class="apps-search-bar">
|
||||||
|
<input type="text" id="appSearchInput" placeholder="Search apps..." autocomplete="off" />
|
||||||
<script defer>
|
<span class="shortcut-indicator-4">Ctrl + S</span>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
</div>
|
||||||
NProgress.configure({ showSpinner: false });
|
<div class="apps-grid">
|
||||||
NProgress.start();
|
</div>
|
||||||
|
</div>
|
||||||
const titleElement = document.querySelector(".search-title");
|
<div id="overlay" class="overlay"></div>
|
||||||
if (titleElement) {
|
<div id="namePrompt" class="popup">
|
||||||
const text = titleElement.textContent.trim();
|
<div class="input-container">
|
||||||
titleElement.textContent = "";
|
<label for="userName">Please enter a name so we know what to call you:</label>
|
||||||
text.split("").forEach((letter, i) => {
|
<div class="input-wrapper">
|
||||||
const span = document.createElement("span");
|
<input type="text" id="userName" placeholder="Your name" oninput="checkInput()" autocomplete="off" />
|
||||||
span.textContent = letter;
|
</div>
|
||||||
span.style.animationDelay = `${i * 0.05}s`;
|
<button id="doneButton" onclick="submitName()" disabled>
|
||||||
titleElement.appendChild(span);
|
<i class="fas fa-check"></i> Done
|
||||||
});
|
</button>
|
||||||
}
|
</div>
|
||||||
|
</div>
|
||||||
window.addEventListener("load", function () {
|
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
|
||||||
NProgress.done();
|
<iframe id="cool-iframe" class="iframe"></iframe>
|
||||||
});
|
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script>
|
||||||
});
|
</body>
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
requestIdleCallback(() => {
|
|
||||||
const ad = document.createElement("script");
|
|
||||||
ad.src = "//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js";
|
|
||||||
ad.async = true;
|
|
||||||
document.body.appendChild(ad);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
244
public/!.html
244
public/!.html
|
@ -1,155 +1,101 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta property="og:title" content="Waves." />
|
<meta property="og:title" content="Waves. - Games"/>
|
||||||
<meta property="og:description" content="A sleek and minimalist web proxy." />
|
<meta property="og:description" content="A sleek and minimalist web proxy."/>
|
||||||
<meta property="og:image" content="/assets/images/icons/favicon.ico" />
|
<meta property="og:image" content="/assets/images/icons/favicon.ico"/>
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff"/>
|
||||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
<meta name="msapplication-TileColor" content="#ffffff"/>
|
||||||
<title>Waves.</title>
|
<title>Waves.</title>
|
||||||
|
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico">
|
||||||
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
<link rel="stylesheet" href="/assets/css/$.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/settings.css">
|
||||||
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
|
<link rel="stylesheet" href="/assets/css/toast.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/g.css">
|
||||||
<link rel="stylesheet" href="/assets/css/$.css" />
|
<link href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css">
|
||||||
<link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
|
||||||
<link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script><script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-WGJ2192JZY');</script>
|
||||||
<link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script>
|
||||||
<link rel="preload" href="/assets/css/g.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
</head>
|
||||||
<noscript>
|
<body>
|
||||||
<link rel="stylesheet" href="/assets/css/settings.css" />
|
<script src="/baremux/index.js"></script>
|
||||||
<link rel="stylesheet" href="/assets/css/toast.css" />
|
<script src="/wah/uv.bundle.js" defer></script>
|
||||||
<link rel="stylesheet" href="/assets/css/nprogress.css" />
|
<script src="/wah/cute1.js" defer></script>
|
||||||
<link rel="stylesheet" href="/assets/css/g.css" />
|
<script src="/assets/js/navbar.js" defer></script>
|
||||||
</noscript>
|
<script src="/assets/js/load.js" defer></script>
|
||||||
|
<script src="/assets/js/eruda.js" defer></script>
|
||||||
<link rel="preload" as="style" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" onload="this.onload=null;this.rel='stylesheet'" />
|
<script src="/assets/js/register.js" defer></script>
|
||||||
<noscript>
|
<script src="/assets/js/settings.js" defer></script>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
|
<script src="/assets/js/greetings.js" defer></script>
|
||||||
</noscript>
|
<script src="/assets/js/shortcuts.js" defer></script>
|
||||||
|
<script src="/assets/js/$.js" defer></script>
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script>
|
<script src="/assets/js/g.js" defer></script>
|
||||||
<script>
|
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
|
||||||
window.dataLayer = window.dataLayer || [];
|
<div class="absolute inset-0 overflow-hidden">
|
||||||
function gtag() {
|
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
|
||||||
dataLayer.push(arguments);
|
</div>
|
||||||
}
|
|
||||||
gtag("js", new Date());
|
|
||||||
gtag("config", "G-WGJ2192JZY");
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script src="/baremux/index.js" defer></script>
|
|
||||||
<script src="/assets/js/nprogress.js?v=0.2.0" defer></script>
|
|
||||||
<script src="/wah/uv.bundle.js" defer></script>
|
|
||||||
<script src="/wah/cute1.js" defer></script>
|
|
||||||
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
|
|
||||||
<script src="/assets/js/register.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/settings.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/greetings.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/shortcuts.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/$.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/g.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/wv.js?v=1.4.1" defer></script>
|
|
||||||
|
|
||||||
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
|
|
||||||
<div class="absolute inset-0 overflow-hidden">
|
|
||||||
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="home-navbar">
|
||||||
|
<img src="/assets/images/icons/favicon.ico" class="favicon">
|
||||||
<div class="home-navbar">
|
<span id="waves">Waves.</span>
|
||||||
<img src="/assets/images/icons/favicon.ico" class="favicon" alt="favicon" />
|
<a href="/" id="home">Home</a>
|
||||||
<span id="waves">Waves.</span>
|
<a href="/g" id="games">Games</a>
|
||||||
<a href="/" id="home">Home</a>
|
<a href="/a" id="apps">Apps</a>
|
||||||
<a href="/g" id="games" style="color: #ffffff;">Games</a>
|
<a href="#" id="movies">Movies</a>
|
||||||
<a href="/s" id="apps">Shortcuts</a>
|
<a href="#" id="ai">AI</a>
|
||||||
<a href="#" id="movies">Movies</a>
|
<a href="#" id="settings-icon">
|
||||||
<a href="#" id="ai">AI</a>
|
<i class="settings-icon fa-regular fa-gear"></i>
|
||||||
<a href="#" id="settings-icon">
|
</a>
|
||||||
<i class="settings-icon fa-regular fa-gear"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="settings-menu" class="settings-menu"></div>
|
|
||||||
|
|
||||||
<div class="navbar">
|
|
||||||
<ul class="nav-buttons">
|
|
||||||
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
|
|
||||||
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
|
|
||||||
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
|
|
||||||
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
|
|
||||||
<li>
|
|
||||||
<div class="small-searchbar" style="position: relative;">
|
|
||||||
<i id="lockIcon" class="fa-solid fa-lock"></i>
|
|
||||||
<input class="waves" type="text" id="searchInputt" placeholder="Search for a query or enter a URL..." autocomplete="off" style="padding-left: 40px;" />
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
|
|
||||||
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
|
|
||||||
<li><a href="/s"><i class="fa-regular fa-rocket"></i></a></li>
|
|
||||||
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content games-page">
|
|
||||||
<h1>Games</h1>
|
|
||||||
<div class="games-search-bar">
|
|
||||||
<input type="text" id="gameSearchInput" placeholder="Search games..." autocomplete="off" />
|
|
||||||
<span class="shortcut-indicator-3">Ctrl + S</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="games-grid"></div>
|
<div id="settings-menu" class="settings-menu"></div>
|
||||||
</div>
|
<div class="navbar">
|
||||||
|
<ul class="nav-buttons">
|
||||||
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
|
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
|
||||||
<div id="overlay" class="overlay"></div>
|
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
|
||||||
|
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
|
||||||
<div id="namePrompt" class="popup">
|
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
|
||||||
<div class="input-container">
|
<li>
|
||||||
<label for="userName">Please enter a name so we know what to call you:</label>
|
<div class="small-searchbar" style="position: relative;">
|
||||||
<div class="input-wrapper">
|
<i id="lockIcon" class="fa-solid fa-lock"></i>
|
||||||
<input type="text" id="userName" placeholder="Your name" autocomplete="off" />
|
<input class="waves" type="text" id="searchInputt"
|
||||||
</div>
|
placeholder="Search for a query or enter a URL..." autocomplete="off"
|
||||||
<button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
|
style="padding-left: 40px;">
|
||||||
|
<span class="shortcut-indicator-2">Ctrl + S</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
|
||||||
|
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
|
||||||
|
<li><a href="/a"><i class="fa-regular fa-grid-2"></i></a></li>
|
||||||
|
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="content games-page">
|
||||||
|
<h1>Games</h1>
|
||||||
<iframe id="cool-iframe" class="iframe"></iframe>
|
<div class="games-search-bar">
|
||||||
|
<input type="text" id="gameSearchInput" placeholder="Search games..." autocomplete="off" />
|
||||||
<script defer>
|
<span class="shortcut-indicator-3">Ctrl + S</span>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
</div>
|
||||||
NProgress.configure({ showSpinner: false });
|
<div class="games-grid">
|
||||||
NProgress.start();
|
</div>
|
||||||
|
</div>
|
||||||
const titleElement = document.querySelector(".search-title");
|
<div id="overlay" class="overlay"></div>
|
||||||
if (titleElement) {
|
<div id="namePrompt" class="popup">
|
||||||
const text = titleElement.textContent.trim();
|
<div class="input-container">
|
||||||
titleElement.textContent = "";
|
<label for="userName">Please enter a name so we know what to call you:</label>
|
||||||
text.split("").forEach((letter, i) => {
|
<div class="input-wrapper">
|
||||||
const span = document.createElement("span");
|
<input type="text" id="userName" placeholder="Your name" oninput="checkInput()" autocomplete="off" />
|
||||||
span.textContent = letter;
|
</div>
|
||||||
span.style.animationDelay = `${i * 0.05}s`;
|
<button id="doneButton" onclick="submitName()" disabled>
|
||||||
titleElement.appendChild(span);
|
<i class="fas fa-check"></i> Done
|
||||||
});
|
</button>
|
||||||
}
|
</div>
|
||||||
|
</div>
|
||||||
window.addEventListener("load", function () {
|
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
|
||||||
NProgress.done();
|
<iframe id="cool-iframe" class="iframe"></iframe>
|
||||||
});
|
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script>
|
||||||
});
|
</div>
|
||||||
</script>
|
</body>
|
||||||
|
|
||||||
<script>
|
|
||||||
requestIdleCallback(() => {
|
|
||||||
const ad = document.createElement("script");
|
|
||||||
ad.src = "//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js";
|
|
||||||
ad.async = true;
|
|
||||||
document.body.appendChild(ad);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
259
public/$.html
259
public/$.html
|
@ -1,172 +1,99 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta property="og:title" content="Waves." />
|
<meta property="og:title" content="Waves."/>
|
||||||
<meta property="og:description" content="A sleek and minimalist web proxy." />
|
<meta property="og:description" content="A sleek and minimalist web proxy."/>
|
||||||
<meta property="og:image" content="/assets/images/icons/favicon.ico" />
|
<meta property="og:image" content="/assets/images/icons/favicon.ico"/>
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff"/>
|
||||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
<meta name="msapplication-TileColor" content="#ffffff"/>
|
||||||
<title>Waves.</title>
|
<title>Waves.</title>
|
||||||
|
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico">
|
||||||
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
<link rel="stylesheet" href="/assets/css/$.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/settings.css">
|
||||||
<link rel="icon" type="image/x-icon" href="/assets/images/icons/favicon.ico" />
|
<link rel="stylesheet" href="/assets/css/toast.css">
|
||||||
|
<link href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="/assets/css/$.css" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
|
||||||
<link rel="preload" href="/assets/css/settings.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script><script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-WGJ2192JZY');</script>
|
||||||
<link rel="preload" href="/assets/css/toast.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
<script type='text/javascript' src='//pl26200262.effectiveratecpm.com/f0/e8/15/f0e81559842363ebf19aa99900ff2d02.js'></script>
|
||||||
<link rel="preload" href="/assets/css/nprogress.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
|
</head>
|
||||||
<noscript>
|
<body>
|
||||||
<link rel="stylesheet" href="/assets/css/settings.css" />
|
<script src="/baremux/index.js"></script>
|
||||||
<link rel="stylesheet" href="/assets/css/toast.css" />
|
<script src="/wah/uv.bundle.js" defer></script>
|
||||||
<link rel="stylesheet" href="/assets/css/nprogress.css" />
|
<script src="/wah/cute1.js" defer></script>
|
||||||
</noscript>
|
<script src="/assets/js/navbar.js" defer></script>
|
||||||
|
<script src="/assets/js/load.js" defer></script>
|
||||||
<link rel="preload" as="style" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" onload="this.onload=null;this.rel='stylesheet'" />
|
<script src="/assets/js/eruda.js" defer></script>
|
||||||
<noscript>
|
<script src="/assets/js/register.js" defer></script>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/aquawolf04/font-awesome-pro@5cd1511/css/all.css" />
|
<script src="/assets/js/settings.js" defer></script>
|
||||||
</noscript>
|
<script src="/assets/js/ping.js" defer></script>
|
||||||
|
<script src="/assets/js/greetings.js" defer></script>
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-WGJ2192JZY"></script>
|
<script src="/assets/js/shortcuts.js" defer></script>
|
||||||
<script>
|
<script src="/assets/js/$.js" defer></script>
|
||||||
window.dataLayer = window.dataLayer || [];
|
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-white transition-bg">
|
||||||
function gtag() {
|
<div class="absolute inset-0 overflow-hidden">
|
||||||
dataLayer.push(arguments);
|
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
|
||||||
}
|
</div>
|
||||||
gtag("js", new Date());
|
|
||||||
gtag("config", "G-WGJ2192JZY");
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script src="/baremux/index.js"></script>
|
|
||||||
<script src="/assets/js/nprogress.js?v=0.2.0" defer></script>
|
|
||||||
<script src="/wah/uv.bundle.js" defer></script>
|
|
||||||
<script src="/wah/cute1.js" defer></script>
|
|
||||||
<script src="/assets/js/eruda.js?v=2.8.4" defer></script>
|
|
||||||
<script src="/assets/js/register.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/settings.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/ping.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/greetings.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/shortcuts.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/$.js?v=2.8.9" defer></script>
|
|
||||||
<script src="/assets/js/wv.js?v=1.4.1" defer></script>
|
|
||||||
|
|
||||||
<div class="relative flex flex-col h-[100vh] items-center justify-center bg-black transition-bg">
|
|
||||||
<div class="absolute inset-0 overflow-hidden">
|
|
||||||
<div class="god-rays absolute -inset-[10px] opacity-50"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="home-navbar">
|
||||||
|
<img src="/assets/images/icons/favicon.ico" class="favicon">
|
||||||
<div class="home-navbar">
|
<span id="waves">Waves.</span>
|
||||||
<img src="/assets/images/icons/favicon.ico" class="favicon" />
|
<a href="/" id="home">Home</a>
|
||||||
<span id="waves">Waves</span>
|
<a href="/g" id="games">Games</a>
|
||||||
<a href="/" id="home" style="color: #ffffff;">Home</a>
|
<a href="/a" id="apps">Apps</a>
|
||||||
<a href="/g" id="games">Games</a>
|
<a href="#" id="movies">Movies</a>
|
||||||
<a href="/s" id="apps">Shortcuts</a>
|
<a href="#" id="ai">AI</a>
|
||||||
<a href="#" id="movies">Movies</a>
|
<a href="#" id="settings-icon">
|
||||||
<a href="#" id="ai">AI</a>
|
<i id="settings-icon" class="settings-icon fa-regular fa-gear"></i>
|
||||||
<a href="#" id="settings-icon"><i class="settings-icon fa-regular fa-gear"></i></a>
|
</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="settings-menu" class="settings-menu"></div>
|
|
||||||
|
|
||||||
<div class="navbar">
|
|
||||||
<ul class="nav-buttons">
|
|
||||||
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
|
|
||||||
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
|
|
||||||
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
|
|
||||||
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
|
|
||||||
<li>
|
|
||||||
<div class="small-searchbar" style="position: relative;">
|
|
||||||
<i id="lockIcon" class="fa-solid fa-lock"></i>
|
|
||||||
<input class="waves" type="text" id="searchInputt" placeholder="Search for a query or enter a URL..." autocomplete="off" style="padding-left: 40px;" />
|
|
||||||
<span class="shortcut-indicator-2">Ctrl + S</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
|
|
||||||
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
|
|
||||||
<li><a href="/s"><i class="fa-regular fa-rocket"></i></a></li>
|
|
||||||
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-container">
|
|
||||||
<div class="search-title">Waves.</div>
|
|
||||||
<div class="search-bar">
|
|
||||||
<input class="waves" type="text" id="searchInput" placeholder="What's been on your mind lately?" autocomplete="off" />
|
|
||||||
<span class="shortcut-indicator">Ctrl + S</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div id="settings-menu" class="settings-menu"></div>
|
||||||
|
<div class="navbar">
|
||||||
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
|
<ul class="nav-buttons">
|
||||||
<div id="overlay" class="overlay"></div>
|
<li><a id="backIcon" href="#"><i class="fa-regular fa-arrow-left"></i></a></li>
|
||||||
|
<li><a id="refreshIcon" href="#"><i class="fa-regular fa-rotate-right"></i></a></li>
|
||||||
<div id="namePrompt" class="popup">
|
<li><a id="forwardIcon" href="#"><i class="fa-regular fa-arrow-right"></i></a></li>
|
||||||
<div class="input-container">
|
<li><a id="fullscreenIcon" href="#"><i class="fa-regular fa-expand"></i></a></li>
|
||||||
<label for="userName">Please enter a name so we know what to call you:</label>
|
<li>
|
||||||
<div class="input-wrapper">
|
<div class="small-searchbar" style="position: relative;">
|
||||||
<input type="text" id="userName" placeholder="Your name" autocomplete="off" />
|
<i id="lockIcon" class="fa-solid fa-lock"></i>
|
||||||
</div>
|
<input class="waves" type="text" id="searchInputt"
|
||||||
<button id="doneButton" onclick="submitName()" disabled><i class="fa-regular fa-check"></i> Done</button>
|
placeholder="Search for a query or enter a URL..." autocomplete="off"
|
||||||
|
style="padding-left: 40px;">
|
||||||
|
<span class="shortcut-indicator-2">Ctrl + S</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li><a href="/"><i class="fa-regular fa-home"></i></a></li>
|
||||||
|
<li><a href="/g"><i class="fa-regular fa-gamepad"></i></a></li>
|
||||||
|
<li><a href="/a"><i class="fa-regular fa-grid-2"></i></a></li>
|
||||||
|
<li><a id="erudaIcon" href="#"><i class="fa-regular fa-code"></i></a></li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="search-container">
|
||||||
|
<div class="search-title">Waves.</div>
|
||||||
<div id="pingDisplay"><i class="fa-regular fa-wifi"></i> Ping: Connecting...</div>
|
<div class="search-bar">
|
||||||
<div id="greeting"></div>
|
<input class="waves" type="text" id="searchInput" placeholder="What's been on your mind lately?" autocomplete="off">
|
||||||
<iframe id="cool-iframe" class="iframe"></iframe>
|
<span class="shortcut-indicator">Ctrl + S</span>
|
||||||
<div id="lastest-commit">Loading latest commit</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div id="copyright">
|
<div id="erudaLoadingScreen" style="display: none;">Eruda is loading...</div>
|
||||||
<i class="fa-regular fa-copyright"></i> 2025
|
<div id="overlay" class="overlay"></div>
|
||||||
<a class="hover-link" href="https://discord.gg/ire" target="_blank" rel="noopener noreferrer"><span class="copyrightname">Waves Services</span></a>.
|
<div id="namePrompt" class="popup">
|
||||||
All Rights Reserved.
|
<div class="input-container">
|
||||||
</div>
|
<label for="userName">Please enter a name so we know what to call you:</label>
|
||||||
|
<div class="input-wrapper">
|
||||||
<div id="discord">
|
<input type="text" id="userName" placeholder="Your name" autocomplete="off">
|
||||||
<a class="hover-link" href="https://discord.gg/ire" target="_blank" rel="noopener noreferrer">
|
</div>
|
||||||
<i class="fa-brands fa-discord"></i> Discord
|
<button id="doneButton" onclick="submitName()" disabled>
|
||||||
</a>
|
<i class="fa-regular fa-check"></i> Done
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
<div id="github">
|
</div>
|
||||||
<a class="hover-link" href="https://github.com/xojw/waves" target="_blank" rel="noopener noreferrer">
|
<div id="pingDisplay">Ping: Connecting...</div>
|
||||||
<i class="fa-brands fa-github"></i> Github
|
<div id="greeting"></div>
|
||||||
</a>
|
<iframe id="cool-iframe" class="iframe"></iframe>
|
||||||
</div>
|
<script type='text/javascript' src='//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js'></script>
|
||||||
|
</body>
|
||||||
<script defer>
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
NProgress.configure({ showSpinner: false });
|
|
||||||
NProgress.start();
|
|
||||||
|
|
||||||
const titleElement = document.querySelector(".search-title");
|
|
||||||
if (titleElement) {
|
|
||||||
const text = titleElement.textContent.trim();
|
|
||||||
titleElement.textContent = "";
|
|
||||||
text.split("").forEach((letter, i) => {
|
|
||||||
const span = document.createElement("span");
|
|
||||||
span.textContent = letter;
|
|
||||||
span.style.animationDelay = `${i * 0.05}s`;
|
|
||||||
titleElement.appendChild(span);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
NProgress.done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
requestIdleCallback(() => {
|
|
||||||
const ad = document.createElement("script");
|
|
||||||
ad.src = "//pl26200346.effectiveratecpm.com/08/db/84/08db842da9b43ad3d13c14634f9fd1c8.js";
|
|
||||||
ad.async = true;
|
|
||||||
document.body.appendChild(ad);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
|
@ -7,7 +7,6 @@ body {
|
||||||
color: #e0e0e0;
|
color: #e0e0e0;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.3s ease;
|
||||||
animation: fadeIn 0.3s ease;
|
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
@ -18,23 +17,6 @@ body {
|
||||||
color: #000000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: #4e4e4e;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #6b6b6b;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nprogress .bar {
|
#nprogress .bar {
|
||||||
background: #ffffff !important;
|
background: #ffffff !important;
|
||||||
z-index: 99999 !important;
|
z-index: 99999 !important;
|
||||||
|
@ -63,7 +45,7 @@ body {
|
||||||
|
|
||||||
.home-navbar {
|
.home-navbar {
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 700px;
|
width: 670px;
|
||||||
top: 1%;
|
top: 1%;
|
||||||
margin-bottom: -10px;
|
margin-bottom: -10px;
|
||||||
margin-left: 50%;
|
margin-left: 50%;
|
||||||
|
@ -72,6 +54,7 @@ body {
|
||||||
height: 35px;
|
height: 35px;
|
||||||
color: #818181;
|
color: #818181;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -86,14 +69,14 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-navbar .favicon {
|
.home-navbar .favicon {
|
||||||
width: 28px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
margin-right: -10px;
|
margin-right: -10px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-navbar a {
|
.home-navbar a {
|
||||||
color: #7c7c7c;
|
color: #e6e6e6;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -104,8 +87,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-navbar a:hover {
|
.home-navbar a:hover {
|
||||||
color: #bbbbbb;
|
font-size: 16px;
|
||||||
font-size: 18px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-navbar a:active {
|
.home-navbar a:active {
|
||||||
|
@ -118,6 +100,23 @@ body {
|
||||||
margin-left: 115px;
|
margin-left: 115px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #4e4e4e;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #6b6b6b;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
top: 1%;
|
top: 1%;
|
||||||
background-color: #1111119c;
|
background-color: #1111119c;
|
||||||
|
@ -223,26 +222,6 @@ body {
|
||||||
color: #818181;
|
color: #818181;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-indicator {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(calc(-50% + 235px), -50%);
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #000000;
|
|
||||||
background-color: #c4c4c4;
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 7px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
animation: fadeIn 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortcut-indicator:hover {
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortcut-indicator-2 {
|
.shortcut-indicator-2 {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
|
@ -256,20 +235,12 @@ body {
|
||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
animation: fadeUp 0.3s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-indicator-2:hover {
|
.shortcut-indicator-2:hover {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arrow-mode {
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 17px;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
animation: fadeIn 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
#lockIcon {
|
#lockIcon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 25px;
|
left: 25px;
|
||||||
|
@ -284,6 +255,7 @@ body {
|
||||||
margin-top: 20%;
|
margin-top: 20%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
@ -293,22 +265,25 @@ body {
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: linear-gradient(-45deg, #8d8d8d, #ffffff);
|
background: linear-gradient(-45deg, #4e4e4e, #ffffff);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-title span {
|
.search-title span {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
opacity: 0;
|
|
||||||
background: inherit;
|
background: inherit;
|
||||||
color: transparent;
|
-webkit-background-clip: text;
|
||||||
transform: translateY(4rem);
|
background-clip: text;
|
||||||
animation: fadeSlideIn 0.6s forwards;
|
-webkit-text-fill-color: transparent;
|
||||||
|
color: transparent;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-50px);
|
||||||
|
animation: fadeInFromLeft 0.5s ease-in-out forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
|
@ -348,6 +323,25 @@ body {
|
||||||
color: #ffffff69;
|
color: #ffffff69;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shortcut-indicator {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(calc(-50% + 235px), -50%);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #000000;
|
||||||
|
background-color: #c4c4c4;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 7px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shortcut-indicator:hover {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
#erudaLoadingScreen {
|
#erudaLoadingScreen {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
|
@ -393,13 +387,13 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.hover-link {
|
.hover-link {
|
||||||
color: #b3b3b3;
|
color: #949494;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: color 0.3s ease;
|
transition: color 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hover-link:hover {
|
.hover-link:hover {
|
||||||
color: #ffffff;
|
color: #dadada;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pingDisplay {
|
#pingDisplay {
|
||||||
|
@ -407,9 +401,10 @@ body {
|
||||||
margin-top: -46px;
|
margin-top: -46px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
font-weight: 550;
|
font-weight: bold;
|
||||||
color: #888888;
|
color: #888888;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
|
@ -417,7 +412,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#pingDisplay:hover {
|
#pingDisplay:hover {
|
||||||
color: #d3d3d3;
|
color: #b6b6b6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.god-rays {
|
.god-rays {
|
||||||
|
@ -431,6 +426,7 @@ body {
|
||||||
background-image: var(--stripes), var(--rays);
|
background-image: var(--stripes), var(--rays);
|
||||||
background-size: 300%, 200%;
|
background-size: 300%, 200%;
|
||||||
background-position: 50% 50%, 50% 50%;
|
background-position: 50% 50%, 50% 50%;
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
mask-image: radial-gradient(ellipse at 100% 0%, transparent 40%, transparent 70%);
|
mask-image: radial-gradient(ellipse at 100% 0%, transparent 40%, transparent 70%);
|
||||||
-webkit-mask-image: radial-gradient(ellipse at 100% 0%, white 40%, transparent 70%);
|
-webkit-mask-image: radial-gradient(ellipse at 100% 0%, white 40%, transparent 70%);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
@ -460,7 +456,7 @@ body {
|
||||||
display: none;
|
display: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.3s ease-in-out;
|
transition: opacity 0.3s ease-in-out;
|
||||||
animation: fadeIn 0.3s ease-in-out forwards;
|
animation: fadeInOverlay 0.3s ease-in-out forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
#namePrompt {
|
#namePrompt {
|
||||||
|
@ -576,6 +572,7 @@ body {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
@ -583,94 +580,42 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#greeting:hover {
|
#greeting:hover {
|
||||||
color: #d3d3d3;
|
color: #b6b6b6;
|
||||||
}
|
}
|
||||||
|
|
||||||
#namePrompt.fade-out {
|
#namePrompt.fade-out {
|
||||||
animation: fadeOut 0.3s ease-in-out forwards;
|
animation: fadeOutPrompt 0.3s ease-in-out forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
#lastest-commit {
|
@keyframes fadeInFromLeft {
|
||||||
position: fixed;
|
0% {
|
||||||
bottom: 10px;
|
opacity: 0;
|
||||||
left: 10px;
|
transform: translateX(-50px);
|
||||||
z-index: 9999;
|
}
|
||||||
background-color: #08080894;
|
|
||||||
border: 1px solid #ffffff21;
|
100% {
|
||||||
color: #cfcfcf;
|
opacity: 1;
|
||||||
font-weight: 540;
|
transform: translateX(0);
|
||||||
transition: all 0.3s ease;
|
}
|
||||||
cursor: default;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-radius: 15px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#copyright {
|
@keyframes fadeIn {
|
||||||
position: fixed;
|
from {
|
||||||
bottom: 10px;
|
opacity: 0;
|
||||||
left: 50%;
|
}
|
||||||
transform: translateX(-50%);
|
|
||||||
z-index: 9999;
|
|
||||||
background-color: #08080894;
|
|
||||||
border: 1px solid #ffffff21;
|
|
||||||
color: #858585;
|
|
||||||
font-weight: 540;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
cursor: default;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-radius: 15px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#copyright:hover {
|
|
||||||
color: #afafaf;
|
|
||||||
}
|
|
||||||
|
|
||||||
#discord {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 10px;
|
|
||||||
right: 100px;
|
|
||||||
z-index: 9999;
|
|
||||||
background-color: #08080894;
|
|
||||||
border: 1px solid #ffffff21;
|
|
||||||
color: #858585;
|
|
||||||
font-weight: 540;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
cursor: default;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-radius: 15px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#github {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 10px;
|
|
||||||
right: 10px;
|
|
||||||
z-index: 9999;
|
|
||||||
background-color: #08080894;
|
|
||||||
border: 1px solid #ffffff21;
|
|
||||||
color: #858585;
|
|
||||||
font-weight: 540;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
cursor: default;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-radius: 15px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fadeIn {
|
|
||||||
animation: fadeIn 0.3s ease-in-out forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fadeOut {
|
|
||||||
animation: fadeOut 0.3s ease-in-out forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeSlideIn {
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInOverlay {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,17 +631,7 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeOutPrompt {
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeOut {
|
|
||||||
0% {
|
0% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
@ -716,6 +651,47 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes swing {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: rotate(3deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: rotate(-3deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes steamLarge {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: 13;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: 39;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes steamSmall {
|
||||||
|
10% {
|
||||||
|
stroke-dashoffset: 9;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
stroke-dashoffset: 27;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: 27;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
.shortcuts-page {
|
.apps-page {
|
||||||
padding: 100px 20px 40px;
|
padding: 100px 20px 40px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcuts-page h1 {
|
.apps-page h1 {
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcuts-grid {
|
.apps-grid {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -21,14 +22,14 @@
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content.shortcuts-page {
|
.content.apps-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-card {
|
.app-card {
|
||||||
background-color: #08080894;
|
background-color: #08080894;
|
||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
padding: 15px 20px;
|
padding: 15px 20px;
|
||||||
|
@ -48,7 +49,7 @@
|
||||||
animation: fadeIn 2s ease;
|
animation: fadeIn 2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-card img {
|
.app-card img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
@ -57,39 +58,40 @@
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-card:hover img {
|
.app-card:hover img {
|
||||||
filter: brightness(1);
|
filter: brightness(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-card:hover {
|
.app-card:hover {
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-card h2 {
|
.app-card h2 {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-card p {
|
.app-card p {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcuts-search-bar {
|
.apps-search-bar {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: #a8a8a8;
|
color: #a8a8a8;
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#shortcutSearchInput {
|
#appSearchInput {
|
||||||
padding: 14px 30px;
|
padding: 14px 30px;
|
||||||
border: 1px solid #ffffff1a;
|
border: 1px solid #ffffff1a;
|
||||||
background-image: url('/assets/images/icons/search.png');
|
background-image: url('/assets/images/icons/search.png');
|
||||||
background-size: 35px 35px;
|
background-size: 35px 35px;
|
||||||
background-position: 5px center;
|
background-position: 10px center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
padding-left: 45px;
|
padding-left: 45px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
@ -102,12 +104,12 @@
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
#shortcutSearchInput:focus,
|
#appSearchInput:focus,
|
||||||
#shortcutSearchInput:hover {
|
#appSearchInput:hover {
|
||||||
border: 1px solid #ffffff69;
|
border: 1px solid #ffffff69;
|
||||||
}
|
}
|
||||||
|
|
||||||
#shortcutSearchInput::placeholder {
|
#appSearchInput::placeholder {
|
||||||
color: #a8a8a8;
|
color: #a8a8a8;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.games-page h1 {
|
.games-page h1 {
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
@ -81,6 +82,7 @@
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: #a8a8a8;
|
color: #a8a8a8;
|
||||||
|
animation: fadeIn 2s ease;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#nprogress{pointer-events:none}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translate(0,-4px);-ms-transform:rotate(3deg) translate(0,-4px);transform:rotate(3deg) translate(0,-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner 400ms linear infinite;animation:nprogress-spinner 400ms linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
|
|
|
@ -63,7 +63,7 @@
|
||||||
|
|
||||||
#close-settings:hover {
|
#close-settings:hover {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
color: #ffffff;
|
color: #d3d3d3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#close-settings i {
|
#close-settings i {
|
||||||
|
@ -94,9 +94,9 @@
|
||||||
|
|
||||||
.transport-selected {
|
.transport-selected {
|
||||||
background-color: #141414;
|
background-color: #141414;
|
||||||
border: 1px solid #ffffff1a;
|
|
||||||
color: #e0e0e0;
|
color: #e0e0e0;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
border: 1px solid #4141411a;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -159,7 +159,7 @@
|
||||||
margin-left: -80px;
|
margin-left: -80px;
|
||||||
background-color: #141414;
|
background-color: #141414;
|
||||||
color: #e0e0e0;
|
color: #e0e0e0;
|
||||||
border: 1px solid #ffffff1a;
|
border: 1px solid #4141411a;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@ -266,7 +266,7 @@
|
||||||
background-color: #1b1b1b;
|
background-color: #1b1b1b;
|
||||||
color: #e0e0e0;
|
color: #e0e0e0;
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
border: 1px solid #ffffff21;
|
border: 1px solid #4141411a;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -280,8 +280,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-button.active {
|
.tab-button.active {
|
||||||
background-color: #5c5c5c;
|
background-color: #333;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
|
transform: translateY(-4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-content {
|
.tab-content {
|
||||||
|
|
|
@ -32,10 +32,6 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toast i {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toast.show {
|
.toast.show {
|
||||||
animation: slideIn 0.3s forwards;
|
animation: slideIn 0.3s forwards;
|
||||||
}
|
}
|
||||||
|
@ -55,21 +51,6 @@
|
||||||
animation: progress 3s linear forwards;
|
animation: progress 3s linear forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toast .toast-close {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: #888888;
|
|
||||||
font-size: 18px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0;
|
|
||||||
margin-left: 10px;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toast-close:hover {
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slideIn {
|
@keyframes slideIn {
|
||||||
0% {
|
0% {
|
||||||
right: -300px;
|
right: -300px;
|
||||||
|
@ -99,3 +80,18 @@
|
||||||
width: 0%;
|
width: 0%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toast .toast-close {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #888888;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: 10px;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toast-close:hover {
|
||||||
|
color: #d3d3d3;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"shortcuts": [
|
"apps": [
|
||||||
{
|
{
|
||||||
"icon": "/assets/images/a/crazygames.jpg",
|
"icon": "/assets/images/a/crazygames.jpg",
|
||||||
"title": "Crazy Games",
|
"title": "Crazy Games",
|
|
@ -13,6 +13,7 @@
|
||||||
<script>
|
<script>
|
||||||
var gameLoaded = false;
|
var gameLoaded = false;
|
||||||
window.addEventListener("beforeunload", function (e) {
|
window.addEventListener("beforeunload", function (e) {
|
||||||
|
if (adsVisible || !gameLoaded || !lockedOccured) return null;
|
||||||
var confirmationMessage = "Are you sure you want to leave? ";
|
var confirmationMessage = "Are you sure you want to leave? ";
|
||||||
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
|
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
|
||||||
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
|
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
|
||||||
|
@ -85,10 +86,52 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<!-- MIDROLL/INTERSTITIAL VIDEO API -->
|
||||||
|
<script src="js/cpmstar.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<div class="ads">
|
||||||
|
<div class="ad-smallscreen">
|
||||||
|
<div class="ad ad-rectangle-bottom"></div>
|
||||||
|
</div>
|
||||||
|
<div class="ad ad-rectangle-upper" id="adRectangleUpper">
|
||||||
|
<!-- 300X250B PLACEMENT TAG - PLACE INTO BODY (ZONE TAG REQUIRED) -->
|
||||||
|
<script>
|
||||||
|
(function (w, pid) {
|
||||||
|
var r = function (c, m) {
|
||||||
|
c = c.split("").reduce(function (a, b) {
|
||||||
|
return ((a << 5) - a + b.charCodeAt(0)) >>> m;
|
||||||
|
}, 0);
|
||||||
|
return (10 + ((c * 7) % 26)).toString(36) + c.toString(36);
|
||||||
|
},
|
||||||
|
y = r(w.location.href.split("#")[0], 1),
|
||||||
|
c = r(w.location.href.split("#")[0] + pid, 0);
|
||||||
|
w.document.write('<div style="width:300px;height:250px" class="' + c + '"></div>');
|
||||||
|
})(window, 83023);
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<div class="ad-largescreen">
|
||||||
|
<div class="ad ad-leaderboard-bottom">
|
||||||
|
<!-- 300X600B PLACEMENT TAG - PLACE INTO BODY (ZONE TAG REQUIRED) -->
|
||||||
|
<script>
|
||||||
|
(function (w, pid) {
|
||||||
|
var r = function (c, m) {
|
||||||
|
c = c.split("").reduce(function (a, b) {
|
||||||
|
return ((a << 5) - a + b.charCodeAt(0)) >>> m;
|
||||||
|
}, 0);
|
||||||
|
return (10 + ((c * 7) % 26)).toString(36) + c.toString(36);
|
||||||
|
},
|
||||||
|
y = r(w.location.href.split("#")[0], 1),
|
||||||
|
c = r(w.location.href.split("#")[0] + pid, 0);
|
||||||
|
w.document.write('<div style="width:300px;height:600px" class="' + c + '"></div>');
|
||||||
|
})(window, 85420);
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div id="interAdsContainer" style="display: none;"></div> -->
|
||||||
<div id="gameContainer"></div>
|
<div id="gameContainer"></div>
|
||||||
<div id="loader">
|
<div id="loader">
|
||||||
<img class="logo" src="logo.png" />
|
<img class="logo" src="logo.png" />
|
||||||
|
@ -179,6 +222,55 @@
|
||||||
|
|
||||||
var refreshNextTime = true;
|
var refreshNextTime = true;
|
||||||
|
|
||||||
|
function showAds() {
|
||||||
|
document.getElementsByClassName("ad-rectangle-bottom")[0].style.display = "block";
|
||||||
|
document.getElementsByClassName("ad-leaderboard-bottom")[0].style.display = "block";
|
||||||
|
document.getElementById("adRectangleUpper").style.display = "block";
|
||||||
|
|
||||||
|
if (typeof counter === "undefined") {
|
||||||
|
startCounter();
|
||||||
|
resumeCounter();
|
||||||
|
} else {
|
||||||
|
resumeCounter();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideAds() {
|
||||||
|
document.getElementsByClassName("ad-rectangle-bottom")[0].style.display = "none";
|
||||||
|
document.getElementsByClassName("ad-leaderboard-bottom")[0].style.display = "none";
|
||||||
|
document.getElementById("adRectangleUpper").style.display = "none";
|
||||||
|
|
||||||
|
pauseCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// hide ads
|
||||||
|
hideAds();
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
//console.log("time since ads refresh = " + timeSinceRefresh + " seconds");
|
||||||
|
//console.log("time ads visible = " + timeAdsVisible + " seconds");
|
||||||
|
|
||||||
|
if (timeSinceRefresh <= 30 || timeAdsVisible <= 2) {
|
||||||
|
//console.log("don't refresh");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.getElementById("adRectangleBottom") != null && window.getComputedStyle(document.getElementsByClassName("ad-smallscreen")[0]).display != "none") {
|
||||||
|
cpmstarAPI({ kind: "adcmd", module: "POOL 83023", command: "refresh" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.getElementById("adLeaderboardBottom") != null && window.getComputedStyle(document.getElementsByClassName("ad-largescreen")[0]).display != "none") {
|
||||||
|
cpmstarAPI({ kind: "adcmd", module: "POOL 85420", command: "refresh" });
|
||||||
|
}
|
||||||
|
|
||||||
|
cpmstarAPI({ kind: "adcmd", module: "POOL 83025", command: "refresh" });
|
||||||
|
|
||||||
|
timeSinceRefresh = 0;
|
||||||
|
timeAdsVisible = 0;
|
||||||
|
//console.log("refresh ads");
|
||||||
|
}
|
||||||
|
|
||||||
window.onfocus = function () {
|
window.onfocus = function () {
|
||||||
//console.log("onfocus");
|
//console.log("onfocus");
|
||||||
resumeCounter();
|
resumeCounter();
|
||||||
|
@ -191,16 +283,26 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
var timeSinceRefresh = 0;
|
var timeSinceRefresh = 0;
|
||||||
|
var timeAdsVisible = 0;
|
||||||
var counter;
|
var counter;
|
||||||
|
var adsVisible = false;
|
||||||
|
|
||||||
function startCounter() {
|
function startCounter() {
|
||||||
timeSinceRefresh++;
|
timeSinceRefresh++;
|
||||||
|
if (adsVisible) timeAdsVisible++;
|
||||||
|
|
||||||
counter = setTimeout(function () {
|
counter = setTimeout(function () {
|
||||||
startCounter();
|
startCounter();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resumeCounter() {
|
||||||
|
adsVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pauseCounter() {
|
||||||
|
adsVisible = false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
|
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
|
||||||
<script src="firebase/firebase-app.js"></script>
|
<script src="firebase/firebase-app.js"></script>
|
||||||
|
|
|
@ -1,485 +1,293 @@
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
window.APP = {};
|
const historyStack = []
|
||||||
|
let currentIndex = -1
|
||||||
const iframe = document.getElementById('cool-iframe');
|
const refreshIcon = document.getElementById('refreshIcon')
|
||||||
const erudaLoadingScreen = document.getElementById('erudaLoadingScreen');
|
const fullscreenIcon = document.getElementById('fullscreenIcon')
|
||||||
const searchInput1 = document.getElementById('searchInput');
|
const backIcon = document.getElementById('backIcon')
|
||||||
const movies = document.getElementById('movies');
|
const forwardIcon = document.getElementById('forwardIcon')
|
||||||
const ai = document.getElementById('ai');
|
const iframe = document.getElementById('cool-iframe')
|
||||||
const topBar = document.querySelector('.topbar');
|
const erudaLoadingScreen = document.getElementById('erudaLoadingScreen')
|
||||||
const refreshIcon = document.getElementById('refreshIcon');
|
if (!refreshIcon || !fullscreenIcon || !backIcon || !forwardIcon || !iframe) return
|
||||||
const fullscreenIcon = document.getElementById('fullscreenIcon');
|
const originalTitle = document.title
|
||||||
const backIcon = document.getElementById('backIcon');
|
let loadingHidden = false
|
||||||
const forwardIcon = document.getElementById('forwardIcon');
|
function showLoadingScreen(withToast = true, showEruda = false) {
|
||||||
const searchInput2 = document.getElementById('searchInputt');
|
loadingHidden = false
|
||||||
const lockIcon = document.getElementById('lockIcon');
|
NProgress.start()
|
||||||
const navbarToggle = document.getElementById('navbar-toggle');
|
document.title = 'Loading... <3'
|
||||||
const navBar = document.querySelector('.navbar');
|
if (withToast) {
|
||||||
|
showToast(
|
||||||
const historyStack = [];
|
'Consider joining our <a href="https://discord.gg/dJvdkPRheV" target="_blank" class="hover-link">Discord</a> <3',
|
||||||
let currentIndex = -1;
|
'success',
|
||||||
const originalTitle = document.title;
|
'heart'
|
||||||
let isLoading = false;
|
)
|
||||||
|
}
|
||||||
if (!iframe || !refreshIcon || !fullscreenIcon || !backIcon || !forwardIcon) {
|
}
|
||||||
return;
|
function hideLoadingScreen() {
|
||||||
}
|
if (loadingHidden) return
|
||||||
|
loadingHidden = true
|
||||||
const animationStyle = document.createElement('style');
|
NProgress.done()
|
||||||
animationStyle.textContent = `
|
document.title = originalTitle
|
||||||
@keyframes slideLeft {0% { transform: translateX(0); } 50% { transform: translateX(-5px); } 100% { transform: translateX(0); }}
|
}
|
||||||
@keyframes slideRight {0% { transform: translateX(0); } 50% { transform: translateX(5px); } 100% { transform: translateX(0); }}
|
refreshIcon.addEventListener('click', () => {
|
||||||
.button-animate-back { animation: slideLeft 0.3s ease-in-out; }
|
refreshIcon.classList.add('spin')
|
||||||
.button-animate-forward { animation: slideRight 0.3s ease-in-out; }
|
if (iframe.tagName === 'IFRAME') {
|
||||||
.spin { animation: spinAnimation 0.3s linear; }
|
const currentUrl = iframe.contentWindow.location.href
|
||||||
@keyframes spinAnimation { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
if (normalizeUrl(currentUrl) !== normalizeUrl(historyStack[currentIndex] || '')) {
|
||||||
`;
|
addToHistory(currentUrl)
|
||||||
document.head.appendChild(animationStyle);
|
}
|
||||||
|
iframe.contentWindow.location.reload(true)
|
||||||
function showLoadingScreen(withToast = true) {
|
}
|
||||||
if (isLoading) return;
|
setTimeout(() => refreshIcon.classList.remove('spin'), 300)
|
||||||
isLoading = true;
|
})
|
||||||
if (typeof NProgress !== 'undefined') NProgress.start();
|
fullscreenIcon.addEventListener('click', () => {
|
||||||
|
if (iframe.requestFullscreen) iframe.requestFullscreen()
|
||||||
if (withToast) {
|
else if (iframe.mozRequestFullScreen) iframe.mozRequestFullScreen()
|
||||||
showToast(
|
else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen()
|
||||||
'Consider joining our <a href="https://discord.gg/dJvdkPRheV" target="_blank" class="hover-link">Discord</a> <3',
|
else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen()
|
||||||
'success',
|
})
|
||||||
'heart'
|
backIcon.addEventListener('click', () => {
|
||||||
);
|
if (currentIndex > 0) {
|
||||||
}
|
currentIndex--
|
||||||
}
|
iframe.src = historyStack[currentIndex]
|
||||||
|
showLoadingScreen(false, false)
|
||||||
function hideLoadingScreen() {
|
updateNavButtons()
|
||||||
if (!isLoading) return;
|
updateDecodedSearchInput()
|
||||||
if (typeof NProgress !== 'undefined') NProgress.done();
|
}
|
||||||
document.title = originalTitle;
|
})
|
||||||
isLoading = false;
|
forwardIcon.addEventListener('click', () => {
|
||||||
if (erudaLoadingScreen) erudaLoadingScreen.style.display = 'none';
|
if (currentIndex < historyStack.length - 1) {
|
||||||
}
|
currentIndex++
|
||||||
|
iframe.src = historyStack[currentIndex]
|
||||||
function normalizeUrl(urlStr) {
|
showLoadingScreen(false, false)
|
||||||
if (!urlStr || urlStr === 'about:blank') return urlStr;
|
updateNavButtons()
|
||||||
try {
|
updateDecodedSearchInput()
|
||||||
const url = new URL(urlStr);
|
}
|
||||||
url.searchParams.delete('ia');
|
})
|
||||||
return url.toString();
|
function normalizeUrl(urlStr) {
|
||||||
} catch {
|
try {
|
||||||
return urlStr;
|
const url = new URL(urlStr)
|
||||||
}
|
url.searchParams.delete('ia')
|
||||||
}
|
return url.toString()
|
||||||
|
} catch {
|
||||||
function decodeUrl(encodedUrl) {
|
return urlStr
|
||||||
if (!encodedUrl) return '';
|
}
|
||||||
try {
|
}
|
||||||
const prefix = (typeof __uv$config !== 'undefined' && __uv$config.prefix) ? __uv$config.prefix : '/wa/a/';
|
function addToHistory(url) {
|
||||||
const decodeFunction = (typeof __uv$config !== 'undefined' && __uv$config.decodeUrl) ? __uv$config.decodeUrl : decodeURIComponent;
|
const normalized = normalizeUrl(url)
|
||||||
const urlObject = new URL(encodedUrl, window.location.origin);
|
if (currentIndex >= 0 && normalizeUrl(historyStack[currentIndex]) === normalized) return
|
||||||
if (urlObject.pathname.startsWith(prefix)) {
|
if (currentIndex < historyStack.length - 1) historyStack.splice(currentIndex + 1)
|
||||||
const encodedPart = urlObject.pathname.slice(prefix.length);
|
historyStack.push(url)
|
||||||
return decodeFunction(encodedPart) + urlObject.search + urlObject.hash;
|
currentIndex++
|
||||||
}
|
updateNavButtons()
|
||||||
} catch {}
|
updateDecodedSearchInput()
|
||||||
try {
|
}
|
||||||
return decodeURIComponent(encodedUrl);
|
function updateNavButtons() {
|
||||||
} catch {
|
backIcon.disabled = currentIndex <= 0
|
||||||
return encodedUrl;
|
forwardIcon.disabled = currentIndex >= historyStack.length - 1
|
||||||
}
|
backIcon.classList.toggle('disabled', currentIndex <= 0)
|
||||||
}
|
forwardIcon.classList.toggle('disabled', currentIndex >= historyStack.length - 1)
|
||||||
|
}
|
||||||
function updateNavButtons() {
|
function updateDecodedSearchInput() {
|
||||||
if (!backIcon || !forwardIcon) return;
|
const searchInput2 = document.getElementById('searchInputt')
|
||||||
const canGoBack = currentIndex > 0;
|
if (!searchInput2) return
|
||||||
const canGoForward = currentIndex < historyStack.length - 1;
|
let url = ''
|
||||||
backIcon.disabled = !canGoBack;
|
if (currentIndex >= 0 && historyStack[currentIndex]) {
|
||||||
forwardIcon.disabled = !canGoForward;
|
url = historyStack[currentIndex]
|
||||||
backIcon.classList.toggle('disabled', !canGoBack);
|
} else if (iframe.src) {
|
||||||
forwardIcon.classList.toggle('disabled', !canGoForward);
|
url = iframe.src
|
||||||
}
|
}
|
||||||
|
searchInput2.value = decodeUrl(url)
|
||||||
function updateDecodedSearchInput() {
|
const lockIcon = document.getElementById('lockIcon')
|
||||||
if (!searchInput2) return;
|
if (lockIcon) {
|
||||||
let currentUrl = '';
|
lockIcon.className = decodeUrl(url).startsWith('https://') ?
|
||||||
if (currentIndex >= 0 && historyStack[currentIndex]) {
|
'fa-regular fa-lock' :
|
||||||
currentUrl = historyStack[currentIndex];
|
'fa-regular fa-lock-open'
|
||||||
} else if (iframe.src && iframe.src !== 'about:blank') {
|
lockIcon.style.color = ''
|
||||||
currentUrl = iframe.src;
|
}
|
||||||
}
|
}
|
||||||
const decoded = decodeUrl(currentUrl);
|
iframe.addEventListener('load', () => {
|
||||||
searchInput2.value = decoded;
|
try {
|
||||||
|
hideLoadingScreen()
|
||||||
if (lockIcon) {
|
} catch {
|
||||||
const isSecure = decoded.startsWith('https://');
|
hideLoadingScreen()
|
||||||
lockIcon.className = isSecure ? 'fa-regular fa-lock' : 'fa-regular fa-lock-open';
|
} finally {
|
||||||
}
|
if (erudaLoadingScreen) erudaLoadingScreen.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
})
|
||||||
function addToHistory(url, isReplacingCurrent = false) {
|
iframe.addEventListener('error', () => {
|
||||||
if (!url || url === 'about:blank') return;
|
hideLoadingScreen()
|
||||||
|
})
|
||||||
const normalizedNewUrl = normalizeUrl(url);
|
iframe.addEventListener('loadstart', () => {
|
||||||
const currentHistoryEntry = historyStack[currentIndex];
|
const navBar = document.querySelector('.navbar')
|
||||||
const normalizedCurrentHistoryEntry = currentIndex >= 0 ? normalizeUrl(currentHistoryEntry) : null;
|
const navbarToggle = document.getElementById('navbar-toggle')
|
||||||
|
if (navbarToggle && navbarToggle.checked && navBar) navBar.style.display = 'block'
|
||||||
if (isReplacingCurrent && currentIndex >= 0) {
|
showLoadingScreen(false, false)
|
||||||
if (normalizedCurrentHistoryEntry !== normalizedNewUrl || currentHistoryEntry !== url) {
|
})
|
||||||
historyStack[currentIndex] = url;
|
const navBar = document.querySelector('.navbar')
|
||||||
} else {
|
const topBar = document.querySelector('.topbar')
|
||||||
return;
|
const searchInput1 = document.getElementById('searchInput')
|
||||||
}
|
const searchInput2 = document.getElementById('searchInputt')
|
||||||
} else {
|
const movies = document.getElementById('movies')
|
||||||
if (normalizedCurrentHistoryEntry === normalizedNewUrl && currentHistoryEntry === url) {
|
const ai = document.getElementById('ai')
|
||||||
return;
|
const navbarToggle = document.getElementById('navbar-toggle')
|
||||||
}
|
if (navbarToggle && navBar) {
|
||||||
if (currentIndex < historyStack.length - 1) {
|
const savedNavbarState = localStorage.getItem('navbarToggled')
|
||||||
historyStack.splice(currentIndex + 1);
|
navbarToggle.checked = savedNavbarState === null ? true : savedNavbarState === 'true'
|
||||||
}
|
navBar.style.display = iframe.style.display === 'block' && navbarToggle.checked ? 'block' : 'none'
|
||||||
historyStack.push(url);
|
navbarToggle.addEventListener('change', () => {
|
||||||
currentIndex++;
|
localStorage.setItem('navbarToggled', navbarToggle.checked)
|
||||||
}
|
navBar.style.display = iframe.style.display === 'block' && navbarToggle.checked ? 'block' : 'none'
|
||||||
updateNavButtons();
|
})
|
||||||
updateDecodedSearchInput();
|
}
|
||||||
}
|
iframe.style.display = 'none'
|
||||||
|
window.addEventListener('load', hideLoadingScreen)
|
||||||
function setupIframeNavigationListeners() {
|
;[searchInput1, searchInput2].forEach(input => {
|
||||||
try {
|
if (input) {
|
||||||
const iframeWindow = iframe.contentWindow;
|
input.addEventListener('keyup', e => {
|
||||||
if (!iframeWindow || iframeWindow === window || iframeWindow.location.href === 'about:blank') return;
|
if (e.key === 'Enter') {
|
||||||
|
const val = input.value.trim()
|
||||||
const handleNav = (isReplace = false) => {
|
if (val) handleSearch(val)
|
||||||
setTimeout(() => {
|
else showToast('Please enter something in the Search Bar.', 'error', 'warning')
|
||||||
try {
|
}
|
||||||
const newUrlInIframe = iframeWindow.location.href;
|
})
|
||||||
if (newUrlInIframe === 'about:blank' && historyStack[currentIndex] === 'about:blank') return;
|
}
|
||||||
addToHistory(newUrlInIframe, isReplace);
|
})
|
||||||
} catch (e) {}
|
if (movies) movies.addEventListener('click', e => {
|
||||||
}, 0);
|
e.preventDefault()
|
||||||
};
|
handleSearch('https://movies.usewaves.site/')
|
||||||
|
})
|
||||||
if (!iframeWindow.history.pushState.__isPatched) {
|
if (ai) ai.addEventListener('click', e => {
|
||||||
const originalPushState = iframeWindow.history.pushState;
|
e.preventDefault()
|
||||||
iframeWindow.history.pushState = function(...args) {
|
handleSearch('https://ai.usewaves.site/')
|
||||||
originalPushState.apply(this, args);
|
})
|
||||||
handleNav(false);
|
function clearBackground() {
|
||||||
};
|
const preserved = [
|
||||||
iframeWindow.history.pushState.__isPatched = true;
|
document.querySelector('.navbar'),
|
||||||
}
|
document.getElementById('cool-iframe'),
|
||||||
if (!iframeWindow.history.replaceState.__isPatched) {
|
document.querySelector('.loading-screen'),
|
||||||
const originalReplaceState = iframeWindow.history.replaceState;
|
erudaLoadingScreen
|
||||||
iframeWindow.history.replaceState = function(...args) {
|
]
|
||||||
originalReplaceState.apply(this, args);
|
Array.from(document.body.children).forEach(child => {
|
||||||
handleNav(true);
|
if (!preserved.includes(child)) child.remove()
|
||||||
};
|
})
|
||||||
iframeWindow.history.replaceState.__isPatched = true;
|
}
|
||||||
}
|
async function handleSearch(query) {
|
||||||
|
if (!query || !query.trim()) {
|
||||||
iframeWindow.removeEventListener('popstate', iframeWindow.__popstateHandler);
|
showToast('Please enter something in the Search Bar.', 'error', 'warning')
|
||||||
iframeWindow.__popstateHandler = () => handleNav(false);
|
return
|
||||||
iframeWindow.addEventListener('popstate', iframeWindow.__popstateHandler);
|
}
|
||||||
|
clearBackground()
|
||||||
iframeWindow.removeEventListener('hashchange', iframeWindow.__hashchangeHandler);
|
let searchURL
|
||||||
iframeWindow.__hashchangeHandler = () => handleNav(false);
|
if (
|
||||||
iframeWindow.addEventListener('hashchange', iframeWindow.__hashchangeHandler);
|
query.startsWith('/assets/g/') ||
|
||||||
} catch (error) {}
|
query.startsWith(window.location.origin + '/assets/g/')
|
||||||
}
|
) {
|
||||||
|
searchURL = query
|
||||||
iframe.addEventListener('loadstart', () => {
|
} else {
|
||||||
showLoadingScreen(false);
|
searchURL = generateSearchUrl(query)
|
||||||
if (navbarToggle && navbarToggle.checked && navBar) {
|
}
|
||||||
navBar.style.display = 'block';
|
if (searchInput2) searchInput2.value = searchURL
|
||||||
}
|
historyStack.length = 0
|
||||||
});
|
currentIndex = -1
|
||||||
|
showLoadingScreen(true, false)
|
||||||
iframe.addEventListener('load', () => {
|
iframe.style.display = 'block'
|
||||||
hideLoadingScreen();
|
if (topBar) topBar.style.display = 'none'
|
||||||
try {
|
backIcon.disabled = forwardIcon.disabled = true
|
||||||
const newUrl = iframe.contentWindow ? iframe.contentWindow.location.href : iframe.src;
|
let finalUrl
|
||||||
if (newUrl && newUrl !== 'about:blank') {
|
try {
|
||||||
if (currentIndex === -1 || normalizeUrl(historyStack[currentIndex]) !== normalizeUrl(newUrl) || historyStack[currentIndex] !== newUrl) {
|
const u = new URL(searchURL, window.location.origin)
|
||||||
addToHistory(newUrl);
|
if (u.origin === window.location.origin && u.pathname.startsWith('/assets/g/')) {
|
||||||
} else if (historyStack[currentIndex] !== newUrl) {
|
finalUrl = u.href
|
||||||
addToHistory(newUrl, true);
|
} else {
|
||||||
}
|
finalUrl = await getUrl(searchURL)
|
||||||
} else if (newUrl === 'about:blank' && historyStack.length > 0 && historyStack[currentIndex] !== 'about:blank') {
|
}
|
||||||
if (currentIndex > 0) {
|
} catch {
|
||||||
const previousUrl = historyStack[currentIndex - 1];
|
finalUrl = await getUrl(searchURL)
|
||||||
currentIndex--;
|
}
|
||||||
iframe.src = previousUrl;
|
iframe.src = finalUrl
|
||||||
return;
|
iframe.onload = () => {
|
||||||
}
|
hideLoadingScreen()
|
||||||
}
|
if (navbarToggle && navbarToggle.checked && navBar) navBar.style.display = 'block'
|
||||||
setupIframeNavigationListeners();
|
generateSubject()
|
||||||
if (navbarToggle && navbarToggle.checked && navBar) {
|
updateDecodedSearchInput()
|
||||||
navBar.style.display = 'block';
|
}
|
||||||
}
|
iframe.onerror = () => {
|
||||||
} catch (error) {} finally {
|
hideLoadingScreen()
|
||||||
updateNavButtons();
|
}
|
||||||
updateDecodedSearchInput();
|
}
|
||||||
}
|
window.handleSearch = handleSearch
|
||||||
});
|
function generateSearchUrl(query) {
|
||||||
|
try {
|
||||||
iframe.addEventListener('error', () => {
|
return new URL(query).toString()
|
||||||
hideLoadingScreen();
|
} catch {
|
||||||
showToast('Error: Could not load page content.', 'error', 'times-circle');
|
try {
|
||||||
updateNavButtons();
|
const u = new URL(`https://${query}`)
|
||||||
updateDecodedSearchInput();
|
if (u.hostname.includes('.')) return u.toString()
|
||||||
});
|
} catch {}
|
||||||
|
}
|
||||||
function toggleButtonAnimation(button, animationClass) {
|
return `https://duckduckgo.com/?q=${encodeURIComponent(query)}&ia=web`
|
||||||
if (button) {
|
}
|
||||||
button.classList.add(animationClass);
|
function showToast(message, type = 'success', iconType = 'check') {
|
||||||
setTimeout(() => button.classList.remove(animationClass), 200);
|
const toast = document.createElement('div')
|
||||||
}
|
toast.className = `toast show ${type}`
|
||||||
}
|
const icons = {
|
||||||
|
success: '<i class="fa-regular fa-check-circle" style="margin-right: 8px;"></i>',
|
||||||
backIcon.addEventListener('click', () => {
|
error: '<i class="fa-regular fa-times-circle" style="margin-right: 8px;"></i>',
|
||||||
toggleButtonAnimation(backIcon, 'button-animate-back');
|
info: '<i class="fa-regular fa-info-circle" style="margin-right: 8px;"></i>',
|
||||||
if (currentIndex > 0) {
|
warning: '<i class="fa-regular fa-exclamation-triangle" style="margin-right: 8px;"></i>',
|
||||||
currentIndex--;
|
heart: '<i class="fa-regular fa-heart" style="margin-right: 8px;"></i>'
|
||||||
showLoadingScreen(false);
|
}
|
||||||
iframe.src = historyStack[currentIndex];
|
const icon = icons[iconType] || icons.heart
|
||||||
updateNavButtons();
|
toast.innerHTML = `${icon}${message} `
|
||||||
updateDecodedSearchInput();
|
const progressBar = document.createElement('div')
|
||||||
}
|
progressBar.className = 'progress-bar'
|
||||||
});
|
toast.appendChild(progressBar)
|
||||||
|
const closeBtn = document.createElement('button')
|
||||||
forwardIcon.addEventListener('click', () => {
|
closeBtn.className = 'toast-close'
|
||||||
toggleButtonAnimation(forwardIcon, 'button-animate-forward');
|
closeBtn.innerHTML = '<i class="fa-solid fa-xmark" style="margin-left: 8px; font-size: 0.8em;"></i>'
|
||||||
if (currentIndex < historyStack.length - 1) {
|
closeBtn.addEventListener('click', () => {
|
||||||
currentIndex++;
|
toast.classList.add('hide')
|
||||||
showLoadingScreen(false);
|
setTimeout(() => toast.remove(), 500)
|
||||||
iframe.src = historyStack[currentIndex];
|
})
|
||||||
updateNavButtons();
|
toast.appendChild(closeBtn)
|
||||||
updateDecodedSearchInput();
|
document.body.appendChild(toast)
|
||||||
}
|
setTimeout(() => {
|
||||||
});
|
toast.classList.add('hide')
|
||||||
|
setTimeout(() => toast.remove(), 500)
|
||||||
refreshIcon.addEventListener('click', () => {
|
}, 3000)
|
||||||
if (refreshIcon) refreshIcon.classList.add('spin');
|
}
|
||||||
if (iframe.contentWindow) {
|
function preloadResources(url) {
|
||||||
showLoadingScreen(false);
|
if (!url) return
|
||||||
const currentIframeUrl = iframe.contentWindow.location.href;
|
try {
|
||||||
if (normalizeUrl(currentIframeUrl) !== normalizeUrl(historyStack[currentIndex] || '')) {
|
const link = document.createElement('link')
|
||||||
addToHistory(currentIframeUrl);
|
link.rel = 'preload'
|
||||||
}
|
link.href = url
|
||||||
iframe.contentWindow.location.reload(true);
|
link.as = 'fetch'
|
||||||
}
|
link.crossOrigin = 'anonymous'
|
||||||
if (refreshIcon) setTimeout(() => refreshIcon.classList.remove('spin'), 300);
|
document.head.appendChild(link)
|
||||||
});
|
} catch {}
|
||||||
|
}
|
||||||
fullscreenIcon.addEventListener('click', () => {
|
function getUrl(url) {
|
||||||
if (iframe.requestFullscreen) iframe.requestFullscreen();
|
return Promise.resolve(__uv$config.prefix + __uv$config.encodeUrl(url))
|
||||||
else if (iframe.mozRequestFullScreen) iframe.mozRequestFullScreen();
|
}
|
||||||
else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen();
|
function generateSubject() {
|
||||||
else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen();
|
const subjects = ['math', 'science', 'history', 'art', 'programming', 'philosophy']
|
||||||
});
|
const random = subjects[Math.floor(Math.random() * subjects.length)]
|
||||||
|
history.replaceState({}, '', '/learning?subject=' + random)
|
||||||
function generateSearchUrl(query) {
|
}
|
||||||
query = query.trim();
|
function decodeUrl(enc) {
|
||||||
if (!query) return `https://duckduckgo.com/?q=&ia=web`;
|
try {
|
||||||
|
const o = new URL(enc, window.location.origin)
|
||||||
if (/^[a-zA-Z]+:\/\//.test(query)) {
|
const p = (__uv$config && __uv$config.prefix) || '/wa/a/'
|
||||||
try {
|
if (o.pathname.startsWith(p)) {
|
||||||
new URL(query);
|
const part = o.pathname.slice(p.length)
|
||||||
return query;
|
return (__uv$config.decodeUrl ? __uv$config.decodeUrl(part) : decodeURIComponent(part))
|
||||||
} catch (e) {}
|
}
|
||||||
}
|
} catch {}
|
||||||
|
return enc
|
||||||
if (/^(localhost|(\d{1,3}\.){3}\d{1,3})(:\d+)?(\/.*)?$/.test(query) || query.toLowerCase() === "localhost") {
|
}
|
||||||
if (!query.toLowerCase().startsWith("http:") && !query.toLowerCase().startsWith("https:")) {
|
window.decodeUrl = decodeUrl
|
||||||
return `http://${query}`;
|
window.addToHistory = addToHistory
|
||||||
}
|
window.updateDecodedSearchInput = updateDecodedSearchInput
|
||||||
return query;
|
window.normalizeUrl = normalizeUrl
|
||||||
}
|
})
|
||||||
|
|
||||||
try {
|
|
||||||
const urlWithHttps = new URL(`https://${query}`);
|
|
||||||
if (urlWithHttps.hostname &&
|
|
||||||
urlWithHttps.hostname.includes('.') &&
|
|
||||||
!urlWithHttps.hostname.endsWith('.') &&
|
|
||||||
urlWithHttps.hostname !== '.' &&
|
|
||||||
urlWithHttps.hostname.split('.').pop().length >= 2 &&
|
|
||||||
!/^\d+$/.test(urlWithHttps.hostname.split('.').pop())
|
|
||||||
) {
|
|
||||||
return urlWithHttps.toString();
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
return `https://duckduckgo.com/?q=${encodeURIComponent(query)}&ia=web`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getUrl(url) {
|
|
||||||
if (typeof __uv$config !== 'undefined' && __uv$config.encodeUrl) {
|
|
||||||
return Promise.resolve(__uv$config.prefix + __uv$config.encodeUrl(url));
|
|
||||||
}
|
|
||||||
return Promise.resolve(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearBackground() {
|
|
||||||
const preservedElements = [
|
|
||||||
navBar, iframe, document.querySelector('.loading-screen'),
|
|
||||||
erudaLoadingScreen, topBar
|
|
||||||
].filter(el => el != null);
|
|
||||||
Array.from(document.body.children).forEach(child => {
|
|
||||||
if (!preservedElements.includes(child) && child.tagName !== 'SCRIPT' && child.tagName !== 'STYLE' && !child.classList.contains('toast')) {
|
|
||||||
child.remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSearch(query) {
|
|
||||||
if (!query || !query.trim()) {
|
|
||||||
showToast('Please enter something in the Search Bar.', 'error', 'warning');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clearBackground();
|
|
||||||
let searchURL = generateSearchUrl(query);
|
|
||||||
|
|
||||||
historyStack.length = 0;
|
|
||||||
currentIndex = -1;
|
|
||||||
updateNavButtons();
|
|
||||||
showLoadingScreen(true);
|
|
||||||
iframe.style.display = 'block';
|
|
||||||
if (topBar) topBar.style.display = 'flex';
|
|
||||||
if (navBar && navbarToggle && navbarToggle.checked) navBar.style.display = 'block';
|
|
||||||
|
|
||||||
let finalUrlToLoad;
|
|
||||||
if (searchURL.startsWith(window.location.origin + '/assets/g/')) {
|
|
||||||
finalUrlToLoad = searchURL;
|
|
||||||
} else if (searchURL.startsWith('/assets/g/')) {
|
|
||||||
finalUrlToLoad = new URL(searchURL, window.location.origin).href;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const tempUrl = new URL(searchURL);
|
|
||||||
if (tempUrl.origin === window.location.origin && tempUrl.pathname.startsWith('/assets/g/')) {
|
|
||||||
finalUrlToLoad = tempUrl.href;
|
|
||||||
} else {
|
|
||||||
finalUrlToLoad = await getUrl(searchURL);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
finalUrlToLoad = await getUrl(searchURL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchInput2) searchInput2.value = decodeUrl(finalUrlToLoad);
|
|
||||||
iframe.src = finalUrlToLoad;
|
|
||||||
}
|
|
||||||
window.APP.handleSearch = handleSearch;
|
|
||||||
|
|
||||||
[searchInput1, searchInput2].forEach(input => {
|
|
||||||
if (input) {
|
|
||||||
input.addEventListener('keyup', e => {
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
const queryValue = input.value.trim();
|
|
||||||
if (queryValue) {
|
|
||||||
APP.handleSearch(queryValue);
|
|
||||||
if (input === searchInput1) searchInput1.value = '';
|
|
||||||
} else {
|
|
||||||
showToast('Please enter something in the Search Bar.', 'error', 'warning');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (input === searchInput2) {
|
|
||||||
input.addEventListener('focus', updateDecodedSearchInput);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (movies) movies.addEventListener('click', e => {
|
|
||||||
e.preventDefault();
|
|
||||||
APP.handleSearch('https://movies.usewaves.site/');
|
|
||||||
});
|
|
||||||
if (ai) ai.addEventListener('click', e => {
|
|
||||||
e.preventDefault();
|
|
||||||
APP.handleSearch('https://ai.usewaves.site/');
|
|
||||||
});
|
|
||||||
|
|
||||||
function showToast(message, type = 'success', iconType = 'check') {
|
|
||||||
const toast = document.createElement('div');
|
|
||||||
toast.className = `toast show ${type}`;
|
|
||||||
const icons = {
|
|
||||||
'check': 'fa-regular fa-check-circle',
|
|
||||||
'times-circle': 'fa-regular fa-times-circle',
|
|
||||||
'info': 'fa-regular fa-info-circle',
|
|
||||||
'warning': 'fa-regular fa-exclamation-triangle',
|
|
||||||
'heart': 'fa-solid fa-heart'
|
|
||||||
};
|
|
||||||
toast.innerHTML = `<i class="${icons[iconType] || icons.heart}" style="margin-right: 8px;"></i>${message}`;
|
|
||||||
const progressBar = document.createElement('div');
|
|
||||||
progressBar.className = 'progress-bar';
|
|
||||||
toast.appendChild(progressBar);
|
|
||||||
const closeBtn = document.createElement('button');
|
|
||||||
closeBtn.className = 'toast-close';
|
|
||||||
closeBtn.innerHTML = '<i class="fa-solid fa-xmark" style="margin-left: 8px; font-size: 0.8em;"></i>';
|
|
||||||
closeBtn.onclick = () => {
|
|
||||||
toast.classList.add('hide');
|
|
||||||
setTimeout(() => toast.remove(), 500);
|
|
||||||
};
|
|
||||||
toast.appendChild(closeBtn);
|
|
||||||
document.body.appendChild(toast);
|
|
||||||
setTimeout(() => {
|
|
||||||
toast.classList.add('hide');
|
|
||||||
setTimeout(() => toast.remove(), 500);
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (navbarToggle && navBar && iframe) {
|
|
||||||
const savedNavbarState = localStorage.getItem('navbarToggled');
|
|
||||||
navbarToggle.checked = savedNavbarState !== 'false';
|
|
||||||
|
|
||||||
const updateNavbarDisplayBasedOnToggle = () => {
|
|
||||||
if (iframe.style.display === 'block') {
|
|
||||||
navBar.style.display = navbarToggle.checked ? 'block' : 'none';
|
|
||||||
} else {
|
|
||||||
navBar.style.display = 'none';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
updateNavbarDisplayBasedOnToggle();
|
|
||||||
|
|
||||||
navbarToggle.addEventListener('change', () => {
|
|
||||||
localStorage.setItem('navbarToggled', navbarToggle.checked.toString());
|
|
||||||
updateNavbarDisplayBasedOnToggle();
|
|
||||||
});
|
|
||||||
|
|
||||||
window.APP.updateNavbarDisplay = updateNavbarDisplayBasedOnToggle;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
|
||||||
let iframeInitiallyHidden = true;
|
|
||||||
if (iframe.src && iframe.src !== 'about:blank') {
|
|
||||||
iframeInitiallyHidden = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iframeInitiallyHidden) {
|
|
||||||
hideLoadingScreen();
|
|
||||||
if (topBar) topBar.style.display = 'flex';
|
|
||||||
iframe.style.display = 'none';
|
|
||||||
} else {
|
|
||||||
if (topBar) topBar.style.display = 'flex';
|
|
||||||
iframe.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.APP.updateNavbarDisplay) window.APP.updateNavbarDisplay();
|
|
||||||
updateNavButtons();
|
|
||||||
updateDecodedSearchInput();
|
|
||||||
});
|
|
||||||
|
|
||||||
window.APP.decodeUrl = decodeUrl;
|
|
||||||
window.APP.normalizeUrl = normalizeUrl;
|
|
||||||
});
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
const res = await fetch('/api/latest-commit');
|
|
||||||
const {
|
|
||||||
updates
|
|
||||||
} = await res.json();
|
|
||||||
const u = updates[0];
|
|
||||||
const commitUrl = `https://github.com/xojw/waves/commit/${u.sha}`;
|
|
||||||
document.getElementById('lastest-commit').innerHTML =
|
|
||||||
`<a href="${commitUrl}" class="hover-link" target="_blank" rel="noopener noreferrer"><i class="fa-solid fa-code-commit"></i> ${u.sha}</a>`;
|
|
||||||
} catch {
|
|
||||||
document.getElementById('lastest-commit').textContent =
|
|
||||||
'Failed to load lastest commit';
|
|
||||||
}
|
|
||||||
})();
|
|
45
public/assets/js/a.js
Normal file
45
public/assets/js/a.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const searchInput = document.getElementById('appSearchInput');
|
||||||
|
const grid = document.querySelector('.apps-grid');
|
||||||
|
let appsData = [];
|
||||||
|
|
||||||
|
fetch('/assets/data/a.json')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
appsData = data.apps;
|
||||||
|
|
||||||
|
searchInput.placeholder = `Search through ${appsData.length} Apps…`;
|
||||||
|
|
||||||
|
displayApps(appsData);
|
||||||
|
|
||||||
|
searchInput.addEventListener('input', function() {
|
||||||
|
const query = searchInput.value.toLowerCase();
|
||||||
|
const filteredApps = appsData.filter(app => {
|
||||||
|
const title = app.title ? app.title.toLowerCase() : '';
|
||||||
|
const description = app.description ? app.description.toLowerCase() : '';
|
||||||
|
return title.includes(query) || description.includes(query);
|
||||||
|
});
|
||||||
|
displayApps(filteredApps);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => console.error('Error loading apps data:', err));
|
||||||
|
|
||||||
|
function displayApps(apps) {
|
||||||
|
grid.innerHTML = '';
|
||||||
|
if (apps.length === 0) {
|
||||||
|
grid.innerHTML = '<p>Zero apps were found matching your search :(</p>';
|
||||||
|
}
|
||||||
|
apps.forEach(app => {
|
||||||
|
const card = document.createElement('div');
|
||||||
|
card.classList.add('app-card');
|
||||||
|
card.innerHTML = `
|
||||||
|
<img src="${app.icon}" alt="${app.title} Icon" />
|
||||||
|
<h2>${app.title}</h2>
|
||||||
|
`;
|
||||||
|
card.addEventListener('click', function() {
|
||||||
|
window.handleSearch(app.link);
|
||||||
|
});
|
||||||
|
grid.appendChild(card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,69 +1,43 @@
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const searchInput = document.getElementById('gameSearchInput');
|
const searchInput = document.getElementById('gameSearchInput');
|
||||||
const grid = document.querySelector('.games-grid');
|
const grid = document.querySelector('.games-grid');
|
||||||
const sentinel = document.createElement('div');
|
let gamesData = [];
|
||||||
let allGames = [];
|
|
||||||
let filteredGames = [];
|
|
||||||
let renderedCount = 0;
|
|
||||||
const BATCH_SIZE = 20;
|
|
||||||
|
|
||||||
const observer = new IntersectionObserver(entries => {
|
fetch('/assets/data/g.json')
|
||||||
if (entries[0].isIntersecting) loadNextBatch();
|
.then(response => response.json())
|
||||||
}, { rootMargin: '500px' });
|
.then(data => {
|
||||||
|
gamesData = data;
|
||||||
|
searchInput.placeholder = `Search through ${gamesData.length} Games…`;
|
||||||
|
displayGames(gamesData);
|
||||||
|
searchInput.addEventListener('input', function() {
|
||||||
|
const query = searchInput.value.toLowerCase();
|
||||||
|
const filtered = gamesData.filter(game => {
|
||||||
|
const name = (game.name || '').toLowerCase();
|
||||||
|
return name.includes(query);
|
||||||
|
});
|
||||||
|
displayGames(filtered);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => console.error('Error loading games data:', err));
|
||||||
|
|
||||||
fetch('/assets/data/g.json')
|
function displayGames(games) {
|
||||||
.then(res => res.json())
|
grid.innerHTML = '';
|
||||||
.then(data => {
|
if (games.length === 0) {
|
||||||
allGames = data;
|
grid.innerHTML = '<p>Zero games were found matching your search :(</p>';
|
||||||
filteredGames = data;
|
return;
|
||||||
searchInput.placeholder = `Search through ${allGames.length} Games…`;
|
}
|
||||||
grid.parentNode.appendChild(sentinel);
|
games.forEach(game => {
|
||||||
observer.observe(sentinel);
|
const card = document.createElement('div');
|
||||||
resetAndRender();
|
card.classList.add('game-card');
|
||||||
})
|
card.innerHTML = `
|
||||||
.catch(err => console.error(err));
|
<img src="/assets/g/${game.directory}/${game.image}" alt="${game.name} Icon" />
|
||||||
|
<h2>${game.name}</h2>
|
||||||
searchInput.addEventListener('input', function() {
|
`;
|
||||||
const q = this.value.toLowerCase();
|
card.addEventListener('click', function() {
|
||||||
filteredGames = allGames.filter(game =>
|
const url = `/assets/g/${game.directory}`;
|
||||||
(game.name || '').toLowerCase().includes(q)
|
window.handleSearch(url);
|
||||||
);
|
});
|
||||||
resetAndRender();
|
grid.appendChild(card);
|
||||||
});
|
});
|
||||||
|
|
||||||
function resetAndRender() {
|
|
||||||
grid.innerHTML = '';
|
|
||||||
renderedCount = 0;
|
|
||||||
if (filteredGames.length === 0) {
|
|
||||||
grid.innerHTML = '<p>Zero games were found matching your search :(</p>';
|
|
||||||
observer.unobserve(sentinel);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
observer.observe(sentinel);
|
|
||||||
loadNextBatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadNextBatch() {
|
|
||||||
const nextCount = Math.min(renderedCount + BATCH_SIZE, filteredGames.length);
|
|
||||||
for (let i = renderedCount; i < nextCount; i++) {
|
|
||||||
const game = filteredGames[i];
|
|
||||||
const card = document.createElement('div');
|
|
||||||
card.classList.add('game-card');
|
|
||||||
card.innerHTML = `
|
|
||||||
<img src="/assets/g/${game.directory}/${game.image}" alt="${game.name} Icon" />
|
|
||||||
<h2>${game.name}</h2>
|
|
||||||
`;
|
|
||||||
card.addEventListener('click', () => {
|
|
||||||
const gameUrl = window.location.origin + `/assets/g/${game.directory}`;
|
|
||||||
APP.handleSearch(gameUrl);
|
|
||||||
});
|
|
||||||
grid.appendChild(card);
|
|
||||||
}
|
|
||||||
renderedCount = nextCount;
|
|
||||||
if (renderedCount >= filteredGames.length) {
|
|
||||||
observer.unobserve(sentinel);
|
|
||||||
} else {
|
|
||||||
grid.parentNode.appendChild(sentinel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
|
@ -1,6 +1,5 @@
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
const storedName = localStorage.getItem('userName');
|
const storedName = localStorage.getItem('userName');
|
||||||
const path = window.location.pathname;
|
|
||||||
if (!storedName) {
|
if (!storedName) {
|
||||||
document.getElementById('overlay').style.display = 'block';
|
document.getElementById('overlay').style.display = 'block';
|
||||||
document.getElementById('namePrompt').style.display = 'block';
|
document.getElementById('namePrompt').style.display = 'block';
|
||||||
|
@ -12,9 +11,7 @@ window.onload = function() {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const welcomeMsg = getWelcomeMessage(storedName);
|
showToast(`Hey, ${storedName}! Welcome back to Waves!`, 'success', 'wave');
|
||||||
const iconType = getIconType(path);
|
|
||||||
showToast(welcomeMsg, 'success', iconType);
|
|
||||||
const greetingElement = document.getElementById('greeting');
|
const greetingElement = document.getElementById('greeting');
|
||||||
if (greetingElement) {
|
if (greetingElement) {
|
||||||
updateGreeting(storedName);
|
updateGreeting(storedName);
|
||||||
|
@ -34,91 +31,13 @@ function submitName() {
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWelcomeMessage(name) {
|
|
||||||
const path = window.location.pathname;
|
|
||||||
if (path === '/g') {
|
|
||||||
return `Have fun playing games, ${name}!`;
|
|
||||||
} else if (path === '/s') {
|
|
||||||
return `Enjoy our collection of, ${name}!`;
|
|
||||||
} else {
|
|
||||||
return `Welcome back, ${name}!`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getIconType(path) {
|
|
||||||
if (path === '/g') return 'game';
|
|
||||||
if (path === '/s') return 'shortcuts';
|
|
||||||
return 'wave';
|
|
||||||
}
|
|
||||||
|
|
||||||
const generalGreetings = [
|
|
||||||
{ text: 'Welcome aboard', icon: '<i class="fa-regular fa-rocket"></i>', suffix: '!' },
|
|
||||||
{ text: 'Hii', icon: '<i class="fa-regular fa-hand-wave"></i>', suffix: '!!' },
|
|
||||||
{ text: 'Hope you enjoy Waves', icon: '<i class="fa-solid fa-heart"></i>', suffix: ' <3' },
|
|
||||||
{ text: 'Consider joining our Discord (discord.gg/ire)', icon: '<i class="fa-solid fa-smile"></i>', suffix: '!' },
|
|
||||||
{ text: 'How you doing today', icon: '<i class="fa-regular fa-question"></i>', suffix: '?' }
|
|
||||||
];
|
|
||||||
|
|
||||||
const timeGreetings = [];
|
|
||||||
|
|
||||||
timeGreetings.push(
|
|
||||||
{ text: 'Good morning, sunshine', icon: '<i class="fa-regular fa-sun"></i>', suffix: ' :D' },
|
|
||||||
{ text: 'Here’s to a bright morning', icon: '<i class="fa-regular fa-cloud-sun"></i>', suffix: '.' },
|
|
||||||
{ text: 'Enjoy your morning', icon: '<i class="fa-regular fa-mug-hot"></i>', suffix: '!' },
|
|
||||||
{ text: 'Your day starts here', icon: '<i class="fa-regular fa-star"></i>', suffix: '!' }
|
|
||||||
);
|
|
||||||
|
|
||||||
timeGreetings.push(
|
|
||||||
{ text: 'Good afternoon', icon: '<i class="fa-regular fa-leaf"></i>', suffix: '!' },
|
|
||||||
{ text: 'Hope your day is going well', icon: '<i class="fa-regular fa-coffee"></i>', suffix: '.' },
|
|
||||||
{ text: 'Keep up the pace', icon: '<i class="fa-regular fa-book"></i>', suffix: '!' },
|
|
||||||
{ text: 'Stay on track today', icon: '<i class="fa-regular fa-sun"></i>', suffix: '.' }
|
|
||||||
);
|
|
||||||
|
|
||||||
timeGreetings.push(
|
|
||||||
{ text: 'Good evening', icon: '<i class="fa-regular fa-cloud-moon"></i>', suffix: '!' },
|
|
||||||
{ text: 'Time to unwind', icon: '<i class="fa-regular fa-fire"></i>', suffix: '.' },
|
|
||||||
{ text: 'Evening’s here—relax', icon: '<i class="fa-regular fa-star"></i>', suffix: '.' },
|
|
||||||
{ text: 'Breathe and recharge', icon: '<i class="fa-regular fa-moon"></i>', suffix: '…' }
|
|
||||||
);
|
|
||||||
|
|
||||||
timeGreetings.push(
|
|
||||||
{ text: 'Good night', icon: '<i class="fa-regular fa-bed"></i>', suffix: '!' },
|
|
||||||
{ text: 'Rest well', icon: '<i class="fa-regular fa-blanket"></i>', suffix: '.' },
|
|
||||||
{ text: 'Sweet dreams', icon: '<i class="fa-regular fa-star-and-crescent"></i>', suffix: '!' },
|
|
||||||
{ text: 'See you tomorrow', icon: '<i class="fa-regular fa-moon"></i>', suffix: '!' }
|
|
||||||
);
|
|
||||||
|
|
||||||
function getGreeting() {
|
|
||||||
const now = new Date();
|
|
||||||
const hour = now.getHours();
|
|
||||||
let pool = [];
|
|
||||||
if (hour >= 5 && hour < 12) {
|
|
||||||
pool = timeGreetings.slice(0, 4);
|
|
||||||
} else if (hour < 17) {
|
|
||||||
pool = timeGreetings.slice(4, 8);
|
|
||||||
} else if (hour < 21) {
|
|
||||||
pool = timeGreetings.slice(8, 12);
|
|
||||||
} else {
|
|
||||||
pool = timeGreetings.slice(12, 16);
|
|
||||||
}
|
|
||||||
if (Math.random() < 0.5) {
|
|
||||||
pool = generalGreetings;
|
|
||||||
}
|
|
||||||
const choice = pool[Math.floor(Math.random() * pool.length)];
|
|
||||||
return { text: choice.text, icon: choice.icon, suffix: choice.suffix };
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateGreeting(name) {
|
function updateGreeting(name) {
|
||||||
const { text, icon, suffix } = getGreeting();
|
const { text, icon } = getGreeting();
|
||||||
const el = document.getElementById('greeting');
|
const el = document.getElementById('greeting');
|
||||||
if (!el) return;
|
if (el) {
|
||||||
if (text === 'Hope you enjoy Waves') {
|
el.innerHTML = `${icon} ${text}, ${name}!`;
|
||||||
el.innerHTML = `${icon} ${text}, ${name}${suffix}`;
|
el.style.opacity = 1;
|
||||||
} else {
|
|
||||||
el.innerHTML = `${icon} ${text}, ${name}${suffix}`;
|
|
||||||
}
|
}
|
||||||
el.style.opacity = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showToast(message, type = 'success', iconType = 'wave') {
|
function showToast(message, type = 'success', iconType = 'wave') {
|
||||||
|
@ -129,11 +48,9 @@ function showToast(message, type = 'success', iconType = 'wave') {
|
||||||
error: '<i class="fas fa-times-circle" style="margin-right: 8px;"></i>',
|
error: '<i class="fas fa-times-circle" style="margin-right: 8px;"></i>',
|
||||||
info: '<i class="fas fa-info-circle" style="margin-right: 8px;"></i>',
|
info: '<i class="fas fa-info-circle" style="margin-right: 8px;"></i>',
|
||||||
warning: '<i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>',
|
warning: '<i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>',
|
||||||
wave: '<i class="fa-regular fa-hand-wave" style="margin-right: 8px;"></i>',
|
wave: '<i class="fa-regular fa-hand-wave" style="margin-right: 8px;"></i>'
|
||||||
game: '<i class="fa-regular fa-gamepad" style="margin-right: 8px;"></i>',
|
|
||||||
apps: '<i class="fa-regular fa-th" style="margin-right: 8px;"></i>'
|
|
||||||
};
|
};
|
||||||
toast.innerHTML = `${icons[iconType] || icons.wave}${message}`;
|
toast.innerHTML = `${icons[iconType] || icons.wave}${message} `;
|
||||||
const progressBar = document.createElement('div');
|
const progressBar = document.createElement('div');
|
||||||
progressBar.className = 'progress-bar';
|
progressBar.className = 'progress-bar';
|
||||||
toast.appendChild(progressBar);
|
toast.appendChild(progressBar);
|
||||||
|
@ -151,3 +68,63 @@ function showToast(message, type = 'success', iconType = 'wave') {
|
||||||
setTimeout(() => toast.remove(), 500);
|
setTimeout(() => toast.remove(), 500);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGreeting() {
|
||||||
|
const now = new Date();
|
||||||
|
const hour = now.getHours();
|
||||||
|
const day = now.getDay();
|
||||||
|
const options = [];
|
||||||
|
|
||||||
|
if (hour >= 5 && hour < 12) {
|
||||||
|
options.push(
|
||||||
|
{ text: 'Good morning, sunshine', icon: '<i class="fa-regular fa-sun"></i>' },
|
||||||
|
{ text: 'Here’s to a bright morning', icon: '<i class="fa-regular fa-cloud-sun"></i>' },
|
||||||
|
{ text: 'Morning vibes only', icon: '<i class="fa-regular fa-mug-hot"></i>' },
|
||||||
|
{ text: 'Your day starts here', icon: '<i class="fa-regular fa-star"></i>' }
|
||||||
|
);
|
||||||
|
} else if (hour < 17) {
|
||||||
|
options.push(
|
||||||
|
{ text: 'Good afternoon', icon: '<i class="fa-regular fa-leaf"></i>' },
|
||||||
|
{ text: 'Hope your day is going well', icon: '<i class="fa-regular fa-coffee"></i>' },
|
||||||
|
{ text: 'Keep up the pace', icon: '<i class="fa-regular fa-book"></i>' },
|
||||||
|
{ text: 'Stay on track today', icon: '<i class="fa-regular fa-sun"></i>' }
|
||||||
|
);
|
||||||
|
} else if (hour < 21) {
|
||||||
|
options.push(
|
||||||
|
{ text: 'Good evening', icon: '<i class="fa-regular fa-cloud-moon"></i>' },
|
||||||
|
{ text: 'Time to unwind', icon: '<i class="fa-regular fa-fire"></i>' },
|
||||||
|
{ text: 'Evening’s here—relax', icon: '<i class="fa-regular fa-star"></i>' },
|
||||||
|
{ text: 'Breathe and recharge', icon: '<i class="fa-regular fa-moon"></i>' }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
options.push(
|
||||||
|
{ text: 'Good night', icon: '<i class="fa-regular fa-bed"></i>' },
|
||||||
|
{ text: 'Rest well', icon: '<i class="fa-regular fa-blanket"></i>' },
|
||||||
|
{ text: 'Sweet dreams', icon: '<i class="fa-regular fa-star-and-crescent"></i>' },
|
||||||
|
{ text: 'See you tomorrow', icon: '<i class="fa-regular fa-moon"></i>' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (day === 4) {
|
||||||
|
options.push(
|
||||||
|
{ text: 'Thursday mode: engaged', icon: '<i class="fa-regular fa-party-popper"></i>' },
|
||||||
|
{ text: 'Almost Friday', icon: '<i class="fa-regular fa-music"></i>' },
|
||||||
|
{ text: 'Keep going', icon: '<i class="fa-regular fa-thumbs-up"></i>' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (day === 0 || day === 6) {
|
||||||
|
options.push(
|
||||||
|
{ text: 'Happy weekend', icon: '<i class="fa-regular fa-umbrella-beach"></i>' },
|
||||||
|
{ text: 'Enjoy some downtime', icon: '<i class="fa-regular fa-cocktail"></i>' }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
options.push(
|
||||||
|
{ text: 'You’ve got this', icon: '<i class="fa-regular fa-hand-holding-heart"></i>' },
|
||||||
|
{ text: 'One step at a time', icon: '<i class="fa-regular fa-walking"></i>' },
|
||||||
|
{ text: 'Summer is coming', icon: '<i class="fa-regular fa-umbrella-beach"></i>' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return options[Math.floor(Math.random() * options.length)];
|
||||||
|
}
|
21
public/assets/js/load.js
Normal file
21
public/assets/js/load.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
NProgress.configure({ showSpinner: false });
|
||||||
|
NProgress.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
NProgress.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
const titleElement = document.querySelector('.search-title');
|
||||||
|
if (titleElement) {
|
||||||
|
const text = titleElement.textContent;
|
||||||
|
titleElement.innerHTML = '';
|
||||||
|
|
||||||
|
text.split('').forEach((letter, index) => {
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.textContent = letter;
|
||||||
|
span.style.animationDelay = `${index * 0.2}s`;
|
||||||
|
titleElement.appendChild(span);
|
||||||
|
});
|
||||||
|
}
|
183
public/assets/js/navbar.js
Normal file
183
public/assets/js/navbar.js
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
@keyframes slideLeft {0% { transform: translateX(0); } 50% { transform: translateX(-5px); } 100% { transform: translateX(0); }}
|
||||||
|
@keyframes slideRight {0% { transform: translateX(0); } 50% { transform: translateX(5px); } 100% { transform: translateX(0); }}
|
||||||
|
.button-animate-back { animation: slideLeft 0.3s ease-in-out; }
|
||||||
|
.button-animate-forward { animation: slideRight 0.3s ease-in-out; }
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
const historyStack = [];
|
||||||
|
let currentIndex = -1;
|
||||||
|
const elements = {
|
||||||
|
refreshIcon: document.getElementById('refreshIcon'),
|
||||||
|
fullscreenIcon: document.getElementById('fullscreenIcon'),
|
||||||
|
backIcon: document.getElementById('backIcon'),
|
||||||
|
forwardIcon: document.getElementById('forwardIcon'),
|
||||||
|
searchInput2: document.getElementById('searchInputt'),
|
||||||
|
iframe: document.getElementById('cool-iframe')
|
||||||
|
};
|
||||||
|
const originalTitle = document.title;
|
||||||
|
let loadingFallbackTimeout;
|
||||||
|
|
||||||
|
elements.refreshIcon.addEventListener('click', handleRefresh);
|
||||||
|
elements.fullscreenIcon.addEventListener('click', handleFullscreen);
|
||||||
|
elements.backIcon.addEventListener('click', handleBack);
|
||||||
|
elements.forwardIcon.addEventListener('click', handleForward);
|
||||||
|
|
||||||
|
function showLoadingScreen() {
|
||||||
|
if (typeof NProgress !== 'undefined') {
|
||||||
|
NProgress.start();
|
||||||
|
document.title = 'Loading... <3';
|
||||||
|
setTimeout(() => {
|
||||||
|
if (typeof NProgress !== 'undefined') NProgress.done();
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideLoadingScreen() {
|
||||||
|
if (typeof NProgress !== 'undefined') NProgress.done();
|
||||||
|
document.title = originalTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRefresh() {
|
||||||
|
elements.refreshIcon.classList.add('spin');
|
||||||
|
const iframe = elements.iframe;
|
||||||
|
const currentUrl = iframe.contentWindow.location.href;
|
||||||
|
if (normalizeUrl(currentUrl) !== normalizeUrl(historyStack[currentIndex] || '')) {
|
||||||
|
addToHistory(currentUrl);
|
||||||
|
}
|
||||||
|
iframe.contentWindow.location.reload(true);
|
||||||
|
setTimeout(() => elements.refreshIcon.classList.remove('spin'), 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFullscreen() {
|
||||||
|
const iframe = elements.iframe;
|
||||||
|
if (iframe && iframe.tagName === 'IFRAME') iframe.requestFullscreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBack() {
|
||||||
|
toggleButtonAnimation(elements.backIcon, 'button-animate-back');
|
||||||
|
if (currentIndex > 0) {
|
||||||
|
currentIndex--;
|
||||||
|
updateIframeSrc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleForward() {
|
||||||
|
toggleButtonAnimation(elements.forwardIcon, 'button-animate-forward');
|
||||||
|
if (currentIndex < historyStack.length - 1) {
|
||||||
|
currentIndex++;
|
||||||
|
updateIframeSrc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleButtonAnimation(button, animationClass) {
|
||||||
|
button.classList.add(animationClass);
|
||||||
|
setTimeout(() => button.classList.remove(animationClass), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeUrl(urlStr) {
|
||||||
|
try {
|
||||||
|
const url = new URL(urlStr);
|
||||||
|
url.searchParams.delete('ia');
|
||||||
|
return url.toString();
|
||||||
|
} catch (e) {
|
||||||
|
return urlStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToHistory(url) {
|
||||||
|
const normalized = normalizeUrl(url);
|
||||||
|
if (currentIndex >= 0 && normalizeUrl(historyStack[currentIndex]) === normalized) return;
|
||||||
|
if (currentIndex < historyStack.length - 1) historyStack.splice(currentIndex + 1);
|
||||||
|
historyStack.push(url);
|
||||||
|
currentIndex++;
|
||||||
|
updateNavButtons();
|
||||||
|
updateDecodedSearchInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateIframeSrc() {
|
||||||
|
showLoadingScreen();
|
||||||
|
elements.iframe.src = historyStack[currentIndex];
|
||||||
|
updateNavButtons();
|
||||||
|
updateDecodedSearchInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateNavButtons() {
|
||||||
|
const isAtStart = currentIndex <= 0;
|
||||||
|
const isAtEnd = currentIndex >= historyStack.length - 1;
|
||||||
|
elements.backIcon.disabled = isAtStart;
|
||||||
|
elements.forwardIcon.disabled = isAtEnd;
|
||||||
|
elements.backIcon.classList.toggle('disabled', isAtStart);
|
||||||
|
elements.forwardIcon.classList.toggle('disabled', isAtEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDecodedSearchInput() {
|
||||||
|
if (elements.searchInput2) {
|
||||||
|
const url = historyStack[currentIndex] || elements.iframe.src;
|
||||||
|
elements.searchInput2.value = decodeUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeUrl(url) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(url);
|
||||||
|
} catch (e) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addToHistory = addToHistory;
|
||||||
|
window.updateDecodedSearchInput = updateDecodedSearchInput;
|
||||||
|
window.normalizeUrl = normalizeUrl;
|
||||||
|
|
||||||
|
function detectIframeNavigation() {
|
||||||
|
try {
|
||||||
|
const iframeWindow = elements.iframe.contentWindow;
|
||||||
|
const pushState = iframeWindow.history.pushState;
|
||||||
|
const replaceState = iframeWindow.history.replaceState;
|
||||||
|
iframeWindow.history.pushState = function() {
|
||||||
|
pushState.apply(this, arguments);
|
||||||
|
handleIframeNavigation(iframeWindow.location.href);
|
||||||
|
};
|
||||||
|
iframeWindow.history.replaceState = function() {
|
||||||
|
replaceState.apply(this, arguments);
|
||||||
|
handleIframeNavigation(iframeWindow.location.href);
|
||||||
|
};
|
||||||
|
iframeWindow.addEventListener('popstate', () => handleIframeNavigation(iframeWindow.location.href));
|
||||||
|
iframeWindow.addEventListener('hashchange', () => handleIframeNavigation(iframeWindow.location.href));
|
||||||
|
} catch (error) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleIframeNavigation(rawUrl) {
|
||||||
|
let urlStr = rawUrl;
|
||||||
|
try {
|
||||||
|
urlStr = decodeUrl(rawUrl);
|
||||||
|
} catch {}
|
||||||
|
try {
|
||||||
|
const u = new URL(urlStr);
|
||||||
|
if (u.hostname.endsWith('duckduckgo.com')) {
|
||||||
|
if (typeof NProgress !== 'undefined') NProgress.done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
if (normalizeUrl(urlStr) !== normalizeUrl(historyStack[currentIndex] || '')) {
|
||||||
|
showLoadingScreen();
|
||||||
|
addToHistory(urlStr);
|
||||||
|
} else {
|
||||||
|
hideLoadingScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.iframe.addEventListener('load', () => {
|
||||||
|
try {
|
||||||
|
detectIframeNavigation();
|
||||||
|
if (historyStack.length === 0) {
|
||||||
|
addToHistory(elements.iframe.contentWindow.location.href);
|
||||||
|
} else {
|
||||||
|
handleIframeNavigation(elements.iframe.contentWindow.location.href);
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
hideLoadingScreen();
|
||||||
|
});
|
|
@ -1 +0,0 @@
|
||||||
!function(n,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():n.NProgress=e()}(this,function(){function n(n,e,t){return e>n?e:n>t?t:n}function e(n){return 100*(-1+n)}function t(n,t,r){var i;return i="translate3d"===c.positionUsing?{transform:"translate3d("+e(n)+"%,0,0)"}:"translate"===c.positionUsing?{transform:"translate("+e(n)+"%,0)"}:{"margin-left":e(n)+"%"},i.transition="all "+t+"ms "+r,i}function r(n,e){var t="string"==typeof n?n:o(n);return t.indexOf(" "+e+" ")>=0}function i(n,e){var t=o(n),i=t+e;r(t,e)||(n.className=i.substring(1))}function s(n,e){var t,i=o(n);r(n,e)&&(t=i.replace(" "+e+" "," "),n.className=t.substring(1,t.length-1))}function o(n){return(" "+(n.className||"")+" ").replace(/\s+/gi," ")}function a(n){n&&n.parentNode&&n.parentNode.removeChild(n)}var u={};u.version="0.2.0";var c=u.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};u.configure=function(n){var e,t;for(e in n)t=n[e],void 0!==t&&n.hasOwnProperty(e)&&(c[e]=t);return this},u.status=null,u.set=function(e){var r=u.isStarted();e=n(e,c.minimum,1),u.status=1===e?null:e;var i=u.render(!r),s=i.querySelector(c.barSelector),o=c.speed,a=c.easing;return i.offsetWidth,l(function(n){""===c.positionUsing&&(c.positionUsing=u.getPositioningCSS()),f(s,t(e,o,a)),1===e?(f(i,{transition:"none",opacity:1}),i.offsetWidth,setTimeout(function(){f(i,{transition:"all "+o+"ms linear",opacity:0}),setTimeout(function(){u.remove(),n()},o)},o)):setTimeout(n,o)}),this},u.isStarted=function(){return"number"==typeof u.status},u.start=function(){u.status||u.set(0);var n=function(){setTimeout(function(){u.status&&(u.trickle(),n())},c.trickleSpeed)};return c.trickle&&n(),this},u.done=function(n){return n||u.status?u.inc(.3+.5*Math.random()).set(1):this},u.inc=function(e){var t=u.status;return t?("number"!=typeof e&&(e=(1-t)*n(Math.random()*t,.1,.95)),t=n(t+e,0,.994),u.set(t)):u.start()},u.trickle=function(){return u.inc(Math.random()*c.trickleRate)},function(){var n=0,e=0;u.promise=function(t){return t&&"resolved"!==t.state()?(0===e&&u.start(),n++,e++,t.always(function(){e--,0===e?(n=0,u.done()):u.set((n-e)/n)}),this):this}}(),u.render=function(n){if(u.isRendered())return document.getElementById("nprogress");i(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=c.template;var r,s=t.querySelector(c.barSelector),o=n?"-100":e(u.status||0),l=document.querySelector(c.parent);return f(s,{transition:"all 0 linear",transform:"translate3d("+o+"%,0,0)"}),c.showSpinner||(r=t.querySelector(c.spinnerSelector),r&&a(r)),l!=document.body&&i(l,"nprogress-custom-parent"),l.appendChild(t),t},u.remove=function(){s(document.documentElement,"nprogress-busy"),s(document.querySelector(c.parent),"nprogress-custom-parent");var n=document.getElementById("nprogress");n&&a(n)},u.isRendered=function(){return!!document.getElementById("nprogress")},u.getPositioningCSS=function(){var n=document.body.style,e="WebkitTransform"in n?"Webkit":"MozTransform"in n?"Moz":"msTransform"in n?"ms":"OTransform"in n?"O":"";return e+"Perspective"in n?"translate3d":e+"Transform"in n?"translate":"margin"};var l=function(){function n(){var t=e.shift();t&&t(n)}var e=[];return function(t){e.push(t),1==e.length&&n()}}(),f=function(){function n(n){return n.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(n,e){return e.toUpperCase()})}function e(n){var e=document.body.style;if(n in e)return n;for(var t,r=i.length,s=n.charAt(0).toUpperCase()+n.slice(1);r--;)if(t=i[r]+s,t in e)return t;return n}function t(t){return t=n(t),s[t]||(s[t]=e(t))}function r(n,e,r){e=t(e),n.style[e]=r}var i=["Webkit","O","Moz","ms"],s={};return function(n,e){var t,i,s=arguments;if(2==s.length)for(t in e)i=e[t],void 0!==i&&e.hasOwnProperty(t)&&r(n,t,i);else r(n,s[1],s[2])}}();return u});
|
|
|
@ -23,7 +23,7 @@
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (data.type === "latency" && typeof data.latency === "number") {
|
if (data.type === "latency" && typeof data.latency === "number") {
|
||||||
pingDisplay.innerHTML = '<i class="fa-solid fa-wifi"></i> Ping: ' + '~' + data.latency + 'ms';
|
pingDisplay.innerHTML = '<i class="fa-regular fa-wifi"></i> Ping: ' + data.latency + ' ms';
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error parsing message:", err);
|
console.error("Error parsing message:", err);
|
||||||
|
|
|
@ -1,80 +1,97 @@
|
||||||
;(function(){
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const origLog = console.log.bind(console);
|
const defaultWispUrl = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/w/`;
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
let currentWispUrl = localStorage.getItem('customWispUrl') || defaultWispUrl;
|
||||||
origLog(
|
const wispUrl = currentWispUrl;
|
||||||
"%c\n" +
|
const connection = new BareMux.BareMuxConnection("/baremux/worker.js");
|
||||||
" ᶻ 𝗓 𐰁 .ᐟ\n" +
|
|
||||||
" |\\ _,,,---,,_\n" +
|
|
||||||
" /, `.-'`' -. ;-;;,_\n" +
|
|
||||||
" |,4- ) )-,_..;\\ ( `'-'\n" +
|
|
||||||
" '---''(_/--' `-`\\_)\n discord.gg/dJvdkPRheV",
|
|
||||||
"color: hotpink; font-size: 16px; display: block; white-space: pre; text-align: center; padding-left: 28%;"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const labelStyle = "background: white; color: black; font-weight: bold; padding: 2px 4px; border-radius: 2px";
|
async function registerSW() {
|
||||||
const messageStyle = "background: black; color: white; padding: 2px 4px; border-radius: 2px";
|
try {
|
||||||
["log","info","warn","error","debug"].forEach(method => {
|
if (!navigator.serviceWorker) {
|
||||||
const orig = console[method].bind(console);
|
console.log("%c[⚠️]%c Service Workers are not supported by this browser.", "color: orange; font-weight: bold;", "color: black;");
|
||||||
console[method] = (...args) => {
|
return;
|
||||||
const text = args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ');
|
}
|
||||||
orig(`%cWaves:%c ${text}`, labelStyle, messageStyle);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function(){
|
await ensureWebSocketConnection(wispUrl);
|
||||||
const defaultWispUrl = `${window.location.protocol==="https:"?"wss":"ws"}://${window.location.host}/w/`;
|
|
||||||
let currentWispUrl = localStorage.getItem("customWispUrl") || defaultWispUrl;
|
|
||||||
const wispUrl = currentWispUrl;
|
|
||||||
const connection = new BareMux.BareMuxConnection("/baremux/worker.js");
|
|
||||||
|
|
||||||
registerSW();
|
console.log("%c[⚙️]%c Registering Service Worker...", "color: #007bff; font-weight: bold;", "color: #007bff;");
|
||||||
|
await navigator.serviceWorker.register("/wah/sw.js", {
|
||||||
|
scope: '/wah/a/'
|
||||||
|
});
|
||||||
|
console.log("%c[✅]%c Service Worker registered successfully.", "color: green; font-weight: bold;", "color: green;");
|
||||||
|
|
||||||
async function registerSW(){
|
const savedTransport = localStorage.getItem('transport') || "epoxy";
|
||||||
try {
|
switchTransport(savedTransport);
|
||||||
if (!navigator.serviceWorker) return console.error("Service Workers are not supported by this browser.");
|
updateTransportUI(savedTransport);
|
||||||
await ensureWebSocketConnection(wispUrl);
|
|
||||||
console.log("Registering Service Worker...");
|
|
||||||
await navigator.serviceWorker.register("/wah/sw.js", { scope: "/wah/a/" });
|
|
||||||
console.log("Service Worker registered successfully.");
|
|
||||||
const savedTransport = localStorage.getItem("transport") || "epoxy";
|
|
||||||
switchTransport(savedTransport);
|
|
||||||
updateTransportUI(savedTransport);
|
|
||||||
console.log(`Using ${capitalizeTransport(savedTransport)} transport.`);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`An error occurred during Service Worker registration or WebSocket connection: ${e.message||e}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ensureWebSocketConnection(url){
|
console.log(`%c[🚀]%c Using ${savedTransport} transport.`, "color: #ffffff 255, 255); font-weight: bold;", "color: #ffffff;");
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
console.log("Establishing WebSocket connection...");
|
|
||||||
const ws = new WebSocket(url);
|
|
||||||
ws.onopen = () => { console.log("WebSocket connection established."); resolve(ws); };
|
|
||||||
ws.onerror = e => { console.error(`Failed to establish WebSocket connection: ${e.message||e}`); reject(e); };
|
|
||||||
ws.onclose = ev => {
|
|
||||||
if (ev.code !== 1000) console.warn(`WebSocket connection closed. Reason: ${ev.reason||"No reason provided"}`);
|
|
||||||
else console.warn("WebSocket connection closed normally.");
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function switchTransport(t){
|
} catch (error) {
|
||||||
const m = { epoxy: "/epoxy/index.mjs", libcurl: "/libcurl/index.mjs" }[t];
|
logError(error, 'An error occurred during Service Worker registration or WebSocket connection');
|
||||||
if (m) connection.setTransport(m, [{ wisp: wispUrl }]);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTransportUI(t){
|
async function ensureWebSocketConnection(url) {
|
||||||
document.querySelector(".transport-selected").textContent = capitalizeTransport(t);
|
return new Promise((resolve, reject) => {
|
||||||
}
|
console.log("%c[🌐]%c Establishing WebSocket connection...", "color: #007bff; font-weight: bold;", "color: #007bff;");
|
||||||
|
const ws = new WebSocket(url);
|
||||||
|
|
||||||
function capitalizeTransport(t){
|
ws.onopen = () => {
|
||||||
return t.charAt(0).toUpperCase() + t.slice(1).toLowerCase();
|
console.log("%c[✅]%c WebSocket connection established.", "color: green; font-weight: bold;", "color: green;");
|
||||||
}
|
resolve(ws);
|
||||||
|
};
|
||||||
|
|
||||||
document.addEventListener("wispUrlChanged", function(e){
|
ws.onerror = (error) => {
|
||||||
currentWispUrl = e.detail;
|
logError(error, 'Failed to establish WebSocket connection');
|
||||||
switchTransport(localStorage.getItem("transport") || "epoxy");
|
reject(error);
|
||||||
});
|
};
|
||||||
});
|
|
||||||
})();
|
ws.onclose = (event) => {
|
||||||
|
if (event.code !== 1000) {
|
||||||
|
console.warn(`%c[⚠️]%c WebSocket connection closed. Reason: ${event.reason || "No reason provided"}`, "color: orange; font-weight: bold;", "color: orange;");
|
||||||
|
} else {
|
||||||
|
console.warn("%c[⚠️]%c WebSocket connection closed normally.", "color: orange; font-weight: bold;", "color: orange;");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function logError(error, message) {
|
||||||
|
console.error(`%c[❌]%c ${message}: ${error.message || error}`, "color: red; font-weight: bold;", "color: red;");
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTransport(transport) {
|
||||||
|
const transportMap = {
|
||||||
|
"epoxy": "/epoxy/index.mjs",
|
||||||
|
"libcurl": "/libcurl/index.mjs"
|
||||||
|
};
|
||||||
|
|
||||||
|
const transportFile = transportMap[transport];
|
||||||
|
if (transportFile) {
|
||||||
|
connection.setTransport(transportFile, [{
|
||||||
|
wisp: wispUrl
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeTransport(newTransport) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem('transport', newTransport);
|
||||||
|
switchTransport(newTransport);
|
||||||
|
updateTransportUI(newTransport);
|
||||||
|
} catch (error) {
|
||||||
|
logError(error, 'An error occurred while storing transport preference');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTransportUI(transport) {
|
||||||
|
const transportSelected = document.querySelector(".transport-selected");
|
||||||
|
transportSelected.textContent = transport.charAt(0).toUpperCase() + transport.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('wispUrlChanged', function(e) {
|
||||||
|
currentWispUrl = e.detail;
|
||||||
|
switchTransport(localStorage.getItem('transport') || "epoxy");
|
||||||
|
});
|
||||||
|
|
||||||
|
registerSW();
|
||||||
|
});
|
|
@ -1,45 +0,0 @@
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const searchInput = document.getElementById('shortcutSearchInput');
|
|
||||||
const grid = document.querySelector('.shortcuts-grid');
|
|
||||||
let shortcutsData = [];
|
|
||||||
|
|
||||||
fetch('/assets/data/s.json')
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
shortcutsData = data.shortcuts;
|
|
||||||
|
|
||||||
searchInput.placeholder = `Search through ${shortcutsData.length} Shortcuts...`;
|
|
||||||
|
|
||||||
displayShortcuts(shortcutsData);
|
|
||||||
|
|
||||||
searchInput.addEventListener('input', function() {
|
|
||||||
const query = searchInput.value.toLowerCase();
|
|
||||||
const filteredShortcuts = shortcutsData.filter(shortcut => {
|
|
||||||
const title = shortcut.title ? shortcut.title.toLowerCase() : '';
|
|
||||||
const description = shortcut.description ? shortcut.description.toLowerCase() : '';
|
|
||||||
return title.includes(query) || description.includes(query);
|
|
||||||
});
|
|
||||||
displayShortcuts(filteredShortcuts);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(err => console.error('Error loading shortcuts data:', err));
|
|
||||||
|
|
||||||
function displayShortcuts(shortcuts) {
|
|
||||||
grid.innerHTML = '';
|
|
||||||
if (shortcuts.length === 0) {
|
|
||||||
grid.innerHTML = '<p>Zero shortcuts were found matching your search :(</p>';
|
|
||||||
}
|
|
||||||
shortcuts.forEach(shortcut => {
|
|
||||||
const card = document.createElement('div');
|
|
||||||
card.classList.add('shortcut-card');
|
|
||||||
card.innerHTML = `
|
|
||||||
<img src="${shortcut.icon}" alt="${shortcut.title} Icon" />
|
|
||||||
<h2>${shortcut.title}</h2>
|
|
||||||
`;
|
|
||||||
card.addEventListener('click', function() {
|
|
||||||
APP.handleSearch(shortcut.link);
|
|
||||||
});
|
|
||||||
grid.appendChild(card);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,350 +1,253 @@
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const settingsMenu = document.getElementById('settings-menu');
|
const settingsMenu = document.getElementById('settings-menu');
|
||||||
settingsMenu.innerHTML = `
|
settingsMenu.innerHTML = `
|
||||||
<h2>Settings</h2>
|
<h2>Settings</h2>
|
||||||
<div class="settings-tabs">
|
<div class="settings-tabs">
|
||||||
<button class="tab-button active" id="proxy-tab">
|
<button class="tab-button active" id="proxy-tab"><i class="fa-regular fa-server"></i> Proxy</button>
|
||||||
<i class="fa-regular fa-server"></i> Proxy
|
<button class="tab-button" id="cloak-tab"><i class="fa-regular fa-user-secret"></i> Cloak</button>
|
||||||
</button>
|
<button class="tab-button" id="appearance-tab"><i class="fa-regular fa-palette"></i> Appearance</button>
|
||||||
<button class="tab-button" id="cloak-tab">
|
<button class="tab-button" id="info-tab"><i class="fa-regular fa-info"></i> Info</button>
|
||||||
<i class="fa-regular fa-user-secret"></i> Cloak
|
</div>
|
||||||
</button>
|
<div id="proxy-content" class="tab-content">
|
||||||
<button class="tab-button" id="appearance-tab">
|
<label for="transport-selector">Transport</label>
|
||||||
<i class="fa-regular fa-palette"></i> Appearance
|
<p>Transport is how the proxy will send information.</p>
|
||||||
</button>
|
<div class="transport-selector">
|
||||||
<button class="tab-button" id="info-tab">
|
<div class="transport-selected">Epoxy</div>
|
||||||
<i class="fa-regular fa-info"></i> Info
|
<div class="transport-options">
|
||||||
</button>
|
<div>Epoxy</div>
|
||||||
</div>
|
<div>Libcurl</div>
|
||||||
|
|
||||||
<div id="proxy-content" class="tab-content">
|
|
||||||
<label for="transport-selector">Transport</label>
|
|
||||||
<p>Transport is how the proxy will send information.</p>
|
|
||||||
<div class="transport-selector">
|
|
||||||
<div class="transport-selected">Epoxy</div>
|
|
||||||
<div class="transport-options">
|
|
||||||
<div>Epoxy</div>
|
|
||||||
<div>Libcurl</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<label for="wisp-server">Wisp Server</label>
|
|
||||||
<p>Enter a different Wisp Server to connect to.</p>
|
|
||||||
<p>Recommended to keep this as default.</p>
|
|
||||||
<input type="text" id="wisp-server" placeholder="Wisp Server URL Here..." autocomplete="off">
|
|
||||||
<button id="save-wisp-url">Save</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="cloak-content" class="tab-content">
|
|
||||||
<label for="aboutblank-toggle">Auto About:Blank</label>
|
|
||||||
<p>Turn this on to go into about:blank every time the page loads (Recommended).</p>
|
|
||||||
<input type="checkbox" id="aboutblank-toggle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="appearance-content" class="tab-content">
|
|
||||||
<label for="navbar-toggle">Navigation Bar</label>
|
|
||||||
<p>Keep this on for the navigation bar when searching (Recommended).</p>
|
|
||||||
<input type="checkbox" id="navbar-toggle">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="info-content" class="tab-content">
|
|
||||||
<label>Version 2.8.7</label>
|
|
||||||
<label
|
|
||||||
onmouseover="this.querySelector('span').style.color='lime'"
|
|
||||||
onmouseout="this.querySelector('span').style.color='green'">
|
|
||||||
Server Status:
|
|
||||||
<span style="color: green; transition: color 0.3s ease; font-size: 0.95em;">Running</span>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
onmouseover="this.querySelector('span').style.color='lime'"
|
|
||||||
onmouseout="this.querySelector('span').style.color='green'">
|
|
||||||
Server Speed:
|
|
||||||
<span id="server-speed" style="color: green; transition: color 0.3s ease; font-size: 0.95em;">Checking...</span>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
onmouseover="this.querySelector('span').style.color='#dadada'"
|
|
||||||
onmouseout="this.querySelector('span').style.color='#949494'">
|
|
||||||
Server Uptime:
|
|
||||||
<span id="server-uptime" style="color: #949494; transition: color 0.3s ease; font-size: 0.95em;">Calculating...</span>
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
onmouseover="this.querySelector('span').style.color='#dadada'"
|
|
||||||
onmouseout="this.querySelector('span').style.color='#949494'">
|
|
||||||
Server Specs:
|
|
||||||
<span id="server-specs" style="color: #949494; transition: color 0.3s ease; font-size: 0.95em;">Loading...</span>
|
|
||||||
</label>
|
|
||||||
<p>Having any problems? Join our Discord Server below or open an issue on GitHub for support.</p>
|
|
||||||
<div style="display: flex; gap: 10px; justify-content: left; align-items: left; margin-top: 10px; margin-bottom: -20px;">
|
|
||||||
<label>
|
|
||||||
<a href="https://discord.gg/dJvdkPRheV" target="_blank" class="hover-link">
|
|
||||||
<i class="fab fa-discord" style="font-size: 20px;"></i>
|
|
||||||
</a>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<a href="https://github.com/xojw/waves" target="_blank" class="hover-link">
|
|
||||||
<i class="fab fa-github" style="font-size: 20px;"></i>
|
|
||||||
</a>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<label for="wisp-server">Wisp Server</label>
|
||||||
<button id="close-settings">
|
<p>Enter a different Wisp Server to connect to.</p>
|
||||||
<i class="fa-regular fa-times"></i>
|
<p>Recommended to keep this as default.</p>
|
||||||
</button>
|
<input type="text" id="wisp-server" placeholder="Wisp Server URL Here..." autocomplete="off">
|
||||||
|
<button id="save-wisp-url">Save</button>
|
||||||
|
</div>
|
||||||
|
<div id="cloak-content" class="tab-content">
|
||||||
|
<label for="aboutblank-toggle">About:Blank</label>
|
||||||
|
<p>Turn this on to go into about:blank every time the page loads (Recommended).</p>
|
||||||
|
<input type="checkbox" id="aboutblank-toggle">
|
||||||
|
</div>
|
||||||
|
<div id="appearance-content" class="tab-content">
|
||||||
|
<label for="navbar-toggle">Navigation Bar</label>
|
||||||
|
<p>Keep this on for the navigation bar when searching (Recommended).</p>
|
||||||
|
<input type="checkbox" id="navbar-toggle">
|
||||||
|
</div>
|
||||||
|
<div id="info-content" class="tab-content">
|
||||||
|
<label>Version 2.3.5</label>
|
||||||
|
<label onmouseover="this.querySelector('span').style.color='lime'" onmouseout="this.querySelector('span').style.color='green'">
|
||||||
|
Server Status: <span style="color: green; transition: color 0.3s ease;">Running</span>
|
||||||
|
</label>
|
||||||
|
<p>If you want to see Waves status please visit <a href="https://status.usewaves.site" target="_blank" class="hover-link">https://status.usewaves.site</a>.</p>
|
||||||
|
<div style="display: flex; gap: 10px; justify-content: left; align-items: left; margin-top: 10px; margin-bottom: -20px;">
|
||||||
|
<label><a href="https://discord.gg/wves" target="_blank" class="hover-link"><i class="fab fa-discord" style="font-size: 20px;"></i></a></label>
|
||||||
|
<label><a href="https://github.com/xojw/waves" target="_blank" class="hover-link"><i class="fab fa-github" style="font-size: 20px;"></i></a></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="close-settings"><i class="fa-regular fa-times"></i></button>
|
||||||
`;
|
`;
|
||||||
|
const settingsIcon = document.getElementById('settings-icon');
|
||||||
|
const closeSettingsButton = document.getElementById('close-settings');
|
||||||
|
const saveButton = document.getElementById('save-wisp-url');
|
||||||
|
const transportSelector = document.querySelector('.transport-selector');
|
||||||
|
const transportSelected = transportSelector.querySelector('.transport-selected');
|
||||||
|
const transportOptions = transportSelector.querySelector('.transport-options');
|
||||||
|
const navbarToggle = document.getElementById('navbar-toggle');
|
||||||
|
const defaultWispUrl = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/w/`;
|
||||||
|
let currentWispUrl = localStorage.getItem('customWispUrl') || defaultWispUrl;
|
||||||
|
const wispInput = document.querySelector("#wisp-server");
|
||||||
|
wispInput.value = currentWispUrl;
|
||||||
|
|
||||||
const settingsIcon = document.getElementById('settings-icon');
|
function isValidUrl(url) {
|
||||||
const closeSettingsBtn = document.getElementById('close-settings');
|
try {
|
||||||
const saveWispBtn = document.getElementById('save-wisp-url');
|
const parsedUrl = new URL(url);
|
||||||
const transportSelector = document.querySelector('.transport-selector');
|
return (parsedUrl.protocol === "wss:" || parsedUrl.protocol === "ws:") && url.endsWith('/');
|
||||||
const transportSelected = transportSelector.querySelector('.transport-selected');
|
} catch (_) {
|
||||||
const transportOptions = transportSelector.querySelector('.transport-options');
|
return false;
|
||||||
const navbarToggle = document.getElementById('navbar-toggle');
|
}
|
||||||
const defaultWispUrl = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/w/`;
|
}
|
||||||
let currentWispUrl = localStorage.getItem('customWispUrl') || defaultWispUrl;
|
|
||||||
const wispInput = document.querySelector("#wisp-server");
|
|
||||||
wispInput.value = currentWispUrl;
|
|
||||||
let isToggling = false;
|
|
||||||
|
|
||||||
navbarToggle.checked = localStorage.getItem('navbarToggled') !== 'false';
|
function updateWispServerUrl(url) {
|
||||||
|
if (isValidUrl(url)) {
|
||||||
|
currentWispUrl = url;
|
||||||
|
localStorage.setItem('customWispUrl', url);
|
||||||
|
document.dispatchEvent(new CustomEvent('wispUrlChanged', {
|
||||||
|
detail: currentWispUrl
|
||||||
|
}));
|
||||||
|
wispInput.value = currentWispUrl;
|
||||||
|
showToast('success', `WISP URL successfully updated to: ${currentWispUrl}`);
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
console.log("%c[❌]%c Invalid WISP URL. Please enter a valid one.", "color: red; font-weight: bold;", "color: inherit;");
|
||||||
|
currentWispUrl = defaultWispUrl;
|
||||||
|
localStorage.setItem('customWispUrl', defaultWispUrl);
|
||||||
|
wispInput.value = defaultWispUrl;
|
||||||
|
showToast('error', "Invalid URL. Reverting back to default...");
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveButton.addEventListener('click', () => {
|
||||||
|
const customUrl = wispInput.value.trim();
|
||||||
|
updateWispServerUrl(customUrl);
|
||||||
|
});
|
||||||
|
settingsIcon.addEventListener('click', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
toggleSettingsMenu();
|
||||||
|
});
|
||||||
|
closeSettingsButton.addEventListener('click', () => {
|
||||||
|
toggleSettingsMenu();
|
||||||
|
});
|
||||||
|
|
||||||
function isValidUrl(url) {
|
function toggleSettingsMenu() {
|
||||||
try {
|
const icon = document.querySelector('#settings-icon i.settings-icon');
|
||||||
const p = new URL(url);
|
if (settingsMenu.classList.contains('open')) {
|
||||||
return (p.protocol === "wss:" || p.protocol === "ws:") && url.endsWith('/');
|
settingsMenu.classList.add('close');
|
||||||
} catch (_) {
|
icon.classList.remove('fa-solid');
|
||||||
return false;
|
icon.classList.add('fa-regular');
|
||||||
}
|
setTimeout(() => {
|
||||||
}
|
settingsMenu.classList.remove('open', 'close');
|
||||||
|
}, 300);
|
||||||
|
} else {
|
||||||
|
settingsMenu.classList.add('open');
|
||||||
|
icon.classList.remove('fa-regular');
|
||||||
|
icon.classList.add('fa-solid');
|
||||||
|
setTimeout(() => {
|
||||||
|
settingsMenu.classList.remove('close');
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transportSelected.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
transportOptions.classList.toggle('transport-show');
|
||||||
|
this.classList.toggle('transport-arrow-active');
|
||||||
|
});
|
||||||
|
const optionDivs = transportOptions.getElementsByTagName('div');
|
||||||
|
for (let i = 0; i < optionDivs.length; i++) {
|
||||||
|
optionDivs[i].addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
const selectedValue = this.innerHTML;
|
||||||
|
transportSelected.innerHTML = selectedValue;
|
||||||
|
localStorage.setItem('transport', selectedValue.toLowerCase());
|
||||||
|
transportOptions.classList.remove('transport-show');
|
||||||
|
transportSelected.classList.remove('transport-arrow-active');
|
||||||
|
const event = new Event('newTransport', {
|
||||||
|
detail: selectedValue.toLowerCase()
|
||||||
|
});
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
showToast('success', `Transport successfully changed to ${selectedValue}`);
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
document.getElementById('proxy-content').classList.add('active');
|
||||||
|
|
||||||
function runScriptIfChecked() {
|
function switchTab(tabId, contentId, otherTabId1, otherContentId1, otherTabId2, otherContentId2, otherTabId3, otherContentId3) {
|
||||||
let inFrame;
|
document.getElementById(otherContentId1).classList.remove('active');
|
||||||
try {
|
document.getElementById(otherContentId2).classList.remove('active');
|
||||||
inFrame = window !== top;
|
document.getElementById(otherContentId3).classList.remove('active');
|
||||||
} catch (e) {
|
document.getElementById(otherTabId1).classList.remove('active');
|
||||||
inFrame = true;
|
document.getElementById(otherTabId2).classList.remove('active');
|
||||||
}
|
document.getElementById(otherTabId3).classList.remove('active');
|
||||||
const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
|
document.getElementById(contentId).classList.add('active');
|
||||||
if (!aboutBlankChecked || inFrame) {
|
document.getElementById(tabId).classList.add('active');
|
||||||
return;
|
}
|
||||||
}
|
document.getElementById('proxy-tab').addEventListener('click', function() {
|
||||||
const defaultTitle = "Google.";
|
switchTab('proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'cloak-tab', 'cloak-content', 'info-tab', 'info-content');
|
||||||
const defaultIcon = "https://www.google.com/favicon.ico";
|
});
|
||||||
const title = localStorage.getItem("siteTitle") || defaultTitle;
|
document.getElementById('cloak-tab').addEventListener('click', function() {
|
||||||
const icon = localStorage.getItem("faviconURL") || defaultIcon;
|
switchTab('cloak-tab', 'cloak-content', 'proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'info-tab', 'info-content');
|
||||||
const iframeSrc = "/";
|
});
|
||||||
const popup = window.open("", "_blank");
|
document.getElementById('appearance-tab').addEventListener('click', function() {
|
||||||
if (!popup || popup.closed) {
|
switchTab('appearance-tab', 'appearance-content', 'proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'info-tab', 'info-content');
|
||||||
alert("Failed to load automask. Please allow popups and try again.");
|
});
|
||||||
return;
|
document.getElementById('info-tab').addEventListener('click', function() {
|
||||||
}
|
switchTab('info-tab', 'info-content', 'proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'cloak-tab', 'cloak-content');
|
||||||
popup.document.head.innerHTML = `
|
});
|
||||||
|
navbarToggle.addEventListener('change', function() {
|
||||||
|
if (this.checked) {
|
||||||
|
showToast('success', 'Navigation Bar is now enabled.');
|
||||||
|
} else {
|
||||||
|
showToast('error', 'Navigation Bar is now disabled.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function runScriptIfChecked() {
|
||||||
|
let inFrame;
|
||||||
|
try {
|
||||||
|
inFrame = window !== top;
|
||||||
|
} catch (e) {
|
||||||
|
inFrame = true;
|
||||||
|
}
|
||||||
|
const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
|
||||||
|
if (!aboutBlankChecked || inFrame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const defaultTitle = "Google.";
|
||||||
|
const defaultIcon = "https://www.google.com/favicon.ico";
|
||||||
|
const title = localStorage.getItem("siteTitle") || defaultTitle;
|
||||||
|
const icon = localStorage.getItem("faviconURL") || defaultIcon;
|
||||||
|
const iframeSrc = "/";
|
||||||
|
const popup = window.open("", "_blank");
|
||||||
|
if (!popup || popup.closed) {
|
||||||
|
alert("Failed to load automask. Please allow popups and try again.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
popup.document.head.innerHTML = `
|
||||||
<title>${title}</title>
|
<title>${title}</title>
|
||||||
<link rel="icon" href="${icon}">
|
<link rel="icon" href="${icon}">
|
||||||
`;
|
`;
|
||||||
popup.document.body.innerHTML = `
|
popup.document.body.innerHTML = `
|
||||||
<iframe style="height: 100%; width: 100%; border: none; position: fixed; top: 0; right: 0; left: 0; bottom: 0;" src="${iframeSrc}"></iframe>
|
<iframe style="height: 100%; width: 100%; border: none; position: fixed; top: 0; right: 0; left: 0; bottom: 0;" src="${iframeSrc}"></iframe>
|
||||||
`;
|
`;
|
||||||
window.location.replace("https://bisd.schoology.com/home");
|
window.location.replace("https://bisd.schoology.com/home");
|
||||||
}
|
}
|
||||||
|
document.getElementById("aboutblank-toggle").addEventListener("change", function() {
|
||||||
|
localStorage.setItem("aboutBlankChecked", JSON.stringify(this.checked));
|
||||||
|
if (this.checked) {
|
||||||
|
showToast('success', 'About:Blank is now enabled.');
|
||||||
|
} else {
|
||||||
|
showToast('error', 'About:Blank is now disabled.');
|
||||||
|
}
|
||||||
|
runScriptIfChecked();
|
||||||
|
});
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
|
||||||
|
document.getElementById("aboutblank-toggle").checked = aboutBlankChecked;
|
||||||
|
runScriptIfChecked();
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById("aboutblank-toggle").addEventListener("change", function() {
|
function showToast(type, message) {
|
||||||
localStorage.setItem("aboutBlankChecked", JSON.stringify(this.checked));
|
const toast = document.createElement('div');
|
||||||
if (this.checked) {
|
toast.className = `toast ${type} show`;
|
||||||
showToast('success', 'Auto About:Blank is now enabled.');
|
const icons = {
|
||||||
} else {
|
success: '<i class="fa-regular fa-check-circle" style="margin-right: 8px;"></i>',
|
||||||
showToast('error', 'Auto About:Blank is now disabled.');
|
error: '<i class="fa-regular fa-times-circle" style="margin-right: 8px;"></i>',
|
||||||
}
|
info: '<i class="fa-regular fa-info-circle" style="margin-right: 8px;"></i>',
|
||||||
runScriptIfChecked();
|
warning: '<i class="fa-regular fa-exclamation-triangle" style="margin-right: 8px;"></i>'
|
||||||
});
|
};
|
||||||
|
const icon = icons[type] || '';
|
||||||
window.addEventListener("load", function() {
|
toast.innerHTML = `${icon}${message}`;
|
||||||
const aboutBlankChecked = JSON.parse(localStorage.getItem("aboutBlankChecked")) || false;
|
const progressBar = document.createElement('div');
|
||||||
document.getElementById("aboutblank-toggle").checked = aboutBlankChecked;
|
progressBar.className = 'progress-bar';
|
||||||
runScriptIfChecked();
|
toast.appendChild(progressBar);
|
||||||
});
|
const closeBtn = document.createElement('button');
|
||||||
|
closeBtn.className = 'toast-close';
|
||||||
function updateWispServerUrl(url) {
|
closeBtn.innerHTML = '<i class="fa-regular fa-xmark" style="margin-left: 8px; font-size: 0.8em;"></i>';
|
||||||
if (isValidUrl(url)) {
|
closeBtn.addEventListener('click', () => {
|
||||||
currentWispUrl = url;
|
toast.classList.remove('show');
|
||||||
localStorage.setItem('customWispUrl', url);
|
toast.classList.add('hide');
|
||||||
document.dispatchEvent(new CustomEvent('wispUrlChanged', {
|
setTimeout(() => {
|
||||||
detail: currentWispUrl
|
toast.remove();
|
||||||
}));
|
}, 500);
|
||||||
showToast('success', `Wisp Server URL changed to: ${currentWispUrl}`);
|
});
|
||||||
} else {
|
toast.appendChild(closeBtn);
|
||||||
currentWispUrl = defaultWispUrl;
|
document.body.appendChild(toast);
|
||||||
localStorage.setItem('customWispUrl', defaultWispUrl);
|
setTimeout(() => {
|
||||||
document.dispatchEvent(new CustomEvent('wispUrlChanged', {
|
toast.classList.remove('show');
|
||||||
detail: currentWispUrl
|
toast.classList.add('hide');
|
||||||
}));
|
setTimeout(() => {
|
||||||
showToast('error', "Invalid URL. Reverting to default...");
|
toast.remove();
|
||||||
}
|
}, 500);
|
||||||
}
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function updateServerInfo() {
|
|
||||||
const speedSpan = document.getElementById('server-speed');
|
|
||||||
const uptimeSpan = document.getElementById('server-uptime');
|
|
||||||
const specsSpan = document.getElementById('server-specs');
|
|
||||||
let uptimeInterval;
|
|
||||||
|
|
||||||
fetch('/api/info')
|
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) throw new Error();
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then(data => {
|
|
||||||
if (data?.speed) {
|
|
||||||
const updateUptimeDisplay = () => {
|
|
||||||
const uptime = Date.now() - data.startTime;
|
|
||||||
const days = Math.floor(uptime / 86400000);
|
|
||||||
const hours = Math.floor((uptime % 86400000) / 3600000);
|
|
||||||
const minutes = Math.floor((uptime % 3600000) / 60000);
|
|
||||||
const seconds = Math.floor((uptime % 60000) / 1000);
|
|
||||||
uptimeSpan.textContent = `${days}d ${hours}h ${minutes}m ${seconds}s`;
|
|
||||||
};
|
|
||||||
|
|
||||||
updateUptimeDisplay();
|
|
||||||
clearInterval(uptimeInterval);
|
|
||||||
uptimeInterval = setInterval(updateUptimeDisplay, 1000);
|
|
||||||
|
|
||||||
speedSpan.textContent = `${data.speed} (${data.averageLatency}ms)`;
|
|
||||||
specsSpan.textContent = data.specs;
|
|
||||||
}
|
|
||||||
setTimeout(updateServerInfo, 10000);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
speedSpan.textContent = 'Connection error';
|
|
||||||
setTimeout(updateServerInfo, 30000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeInfo() {
|
|
||||||
const infoTab = document.getElementById('info-tab');
|
|
||||||
const infoContent = document.getElementById('info-content');
|
|
||||||
|
|
||||||
const startMonitoring = () => {
|
|
||||||
updateServerInfo();
|
|
||||||
infoTab.removeEventListener('click', startMonitoring);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (infoContent.classList.contains('active')) {
|
|
||||||
updateServerInfo();
|
|
||||||
} else {
|
|
||||||
infoTab.addEventListener('click', startMonitoring, {
|
|
||||||
once: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showToast(type, message) {
|
|
||||||
const toast = document.createElement('div');
|
|
||||||
toast.className = `toast ${type} show`;
|
|
||||||
const icons = {
|
|
||||||
success: '<i class="fa-regular fa-check-circle"></i>',
|
|
||||||
error: '<i class="fa-regular fa-times-circle"></i>',
|
|
||||||
info: '<i class="fa-regular fa-info-circle"></i>',
|
|
||||||
warning: '<i class="fa-regular fa-exclamation-triangle"></i>'
|
|
||||||
};
|
|
||||||
toast.innerHTML = `${icons[type]||''}${message}`;
|
|
||||||
const progressBar = document.createElement('div');
|
|
||||||
progressBar.className = 'progress-bar';
|
|
||||||
toast.appendChild(progressBar);
|
|
||||||
const closeBtn = document.createElement('button');
|
|
||||||
closeBtn.className = 'toast-close';
|
|
||||||
closeBtn.innerHTML = '<i class="fa-regular fa-xmark"></i>';
|
|
||||||
closeBtn.addEventListener('click', () => {
|
|
||||||
toast.classList.replace('show', 'hide');
|
|
||||||
setTimeout(() => toast.remove(), 500);
|
|
||||||
});
|
|
||||||
toast.appendChild(closeBtn);
|
|
||||||
document.body.appendChild(toast);
|
|
||||||
setTimeout(() => {
|
|
||||||
toast.classList.replace('show', 'hide');
|
|
||||||
setTimeout(() => toast.remove(), 500);
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
saveWispBtn.addEventListener('click', () => updateWispServerUrl(wispInput.value.trim()));
|
|
||||||
settingsIcon.addEventListener('click', e => {
|
|
||||||
e.preventDefault();
|
|
||||||
toggleSettingsMenu();
|
|
||||||
});
|
|
||||||
closeSettingsBtn.addEventListener('click', toggleSettingsMenu);
|
|
||||||
|
|
||||||
function toggleSettingsMenu() {
|
|
||||||
if (isToggling) return;
|
|
||||||
isToggling = true;
|
|
||||||
const icon = document.querySelector('#settings-icon i.settings-icon');
|
|
||||||
if (settingsMenu.classList.contains('open')) {
|
|
||||||
settingsMenu.classList.add('close');
|
|
||||||
icon.classList.replace('fa-solid', 'fa-regular');
|
|
||||||
setTimeout(() => {
|
|
||||||
settingsMenu.classList.remove('open', 'close');
|
|
||||||
isToggling = false;
|
|
||||||
}, 300);
|
|
||||||
} else {
|
|
||||||
settingsMenu.classList.add('open');
|
|
||||||
icon.classList.replace('fa-regular', 'fa-solid');
|
|
||||||
setTimeout(() => {
|
|
||||||
settingsMenu.classList.remove('close');
|
|
||||||
isToggling = false;
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transportSelected.addEventListener('click', e => {
|
|
||||||
e.stopPropagation();
|
|
||||||
transportOptions.classList.toggle('transport-show');
|
|
||||||
transportSelected.classList.toggle('transport-arrow-active');
|
|
||||||
});
|
|
||||||
|
|
||||||
Array.from(transportOptions.getElementsByTagName('div')).forEach(option => {
|
|
||||||
option.addEventListener('click', function(e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
const val = this.textContent;
|
|
||||||
transportSelected.textContent = val;
|
|
||||||
localStorage.setItem('transport', val.toLowerCase());
|
|
||||||
transportOptions.classList.remove('transport-show');
|
|
||||||
transportSelected.classList.remove('transport-arrow-active');
|
|
||||||
document.dispatchEvent(new CustomEvent('newTransport', {
|
|
||||||
detail: val.toLowerCase()
|
|
||||||
}));
|
|
||||||
showToast('success', `Transport changed to ${val}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('proxy-content').classList.add('active');
|
|
||||||
|
|
||||||
function switchTab(activeTab, activeContent, ...others) {
|
|
||||||
others.forEach(id => document.getElementById(id).classList.remove('active'));
|
|
||||||
document.getElementById(activeTab).classList.add('active');
|
|
||||||
document.getElementById(activeContent).classList.add('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('proxy-tab').addEventListener('click', () => switchTab('proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'appearance-tab', 'appearance-content', 'info-tab', 'info-content'));
|
|
||||||
document.getElementById('cloak-tab').addEventListener('click', () => switchTab('cloak-tab', 'cloak-content', 'proxy-tab', 'proxy-content', 'appearance-tab', 'appearance-content', 'info-tab', 'info-content'));
|
|
||||||
document.getElementById('appearance-tab').addEventListener('click', () => switchTab('appearance-tab', 'appearance-content', 'proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'info-tab', 'info-content'));
|
|
||||||
document.getElementById('info-tab').addEventListener('click', () => switchTab('info-tab', 'info-content', 'proxy-tab', 'proxy-content', 'cloak-tab', 'cloak-content', 'appearance-tab', 'appearance-content'));
|
|
||||||
|
|
||||||
document.querySelectorAll('.tab-button').forEach(btn => {
|
|
||||||
btn.addEventListener('click', function() {
|
|
||||||
const icon = this.querySelector('i');
|
|
||||||
if (!icon.classList.contains('fa-bounce')) {
|
|
||||||
icon.classList.add('fa-bounce');
|
|
||||||
setTimeout(() => icon.classList.remove('fa-bounce'), 750);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
navbarToggle.addEventListener('change', function() {
|
|
||||||
localStorage.setItem('navbarToggled', this.checked.toString());
|
|
||||||
showToast(this.checked ? 'success' : 'error', `Navigation Bar ${this.checked ? 'enabled' : 'disabled'}`);
|
|
||||||
if (window.APP && typeof window.APP.updateNavbarDisplay === 'function') {
|
|
||||||
window.APP.updateNavbarDisplay();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
initializeInfo();
|
|
||||||
});
|
});
|
|
@ -1,147 +1,109 @@
|
||||||
(function(){
|
(function () {
|
||||||
document.addEventListener('DOMContentLoaded', function(){
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const indicators = document.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4');
|
function getSearchInputs() {
|
||||||
const arrowIndicators = document.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2');
|
return [
|
||||||
indicators.forEach(el => {
|
document.getElementById('searchInput'),
|
||||||
if (!el.dataset.original) el.dataset.original = el.innerHTML;
|
document.getElementById('searchInputt'),
|
||||||
});
|
document.getElementById('gameSearchInput'),
|
||||||
|
document.getElementById('appSearchInput')
|
||||||
function getSearchInputs(){
|
].filter(Boolean);
|
||||||
return [
|
|
||||||
document.getElementById('searchInput'),
|
|
||||||
document.getElementById('searchInputt'),
|
|
||||||
document.getElementById('gameSearchInput'),
|
|
||||||
document.getElementById('shortcutSearchInput')
|
|
||||||
].filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isVisible(el){
|
|
||||||
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
|
|
||||||
}
|
|
||||||
|
|
||||||
function focusFirstVisibleInput(){
|
|
||||||
const inputs = getSearchInputs();
|
|
||||||
for (let inp of inputs) {
|
|
||||||
if (isVisible(inp)) {
|
|
||||||
inp.focus();
|
|
||||||
return inp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (inputs[0]) {
|
|
||||||
inputs[0].focus();
|
function isVisible(el) {
|
||||||
return inputs[0];
|
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let arrowMode = false;
|
function focusFirstVisibleInput() {
|
||||||
|
const inputs = getSearchInputs();
|
||||||
|
for (const input of inputs) {
|
||||||
|
if (isVisible(input)) {
|
||||||
|
input.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inputs.length) {
|
||||||
|
inputs[0].focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateIndicatorState(){
|
document.addEventListener('keydown', function (e) {
|
||||||
const hasText = getSearchInputs().some(i => i.value.trim() !== '');
|
if (e.key === 'Escape') {
|
||||||
if (hasText === arrowMode) return;
|
const inputs = getSearchInputs();
|
||||||
arrowMode = hasText;
|
const active = document.activeElement;
|
||||||
arrowIndicators.forEach(ind => {
|
if (inputs.includes(active)) {
|
||||||
ind.classList.remove('fadeIn');
|
active.blur();
|
||||||
ind.classList.add('fadeOut');
|
e.preventDefault();
|
||||||
setTimeout(() => {
|
return;
|
||||||
if (hasText) {
|
}
|
||||||
ind.innerHTML = '<i class="fa-solid fa-arrow-right"></i>';
|
}
|
||||||
ind.classList.add('arrow-mode');
|
|
||||||
} else {
|
if (e.ctrlKey && e.key.toLowerCase() === 's') {
|
||||||
ind.innerHTML = ind.dataset.original;
|
e.preventDefault();
|
||||||
ind.classList.remove('arrow-mode');
|
focusFirstVisibleInput();
|
||||||
}
|
}
|
||||||
ind.classList.remove('fadeOut');
|
|
||||||
ind.classList.add('fadeIn');
|
|
||||||
}, 100);
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function triggerSubmit(input){
|
document.querySelectorAll(
|
||||||
const query = input.value.trim();
|
'.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4'
|
||||||
if (!query) {
|
).forEach(function (el) {
|
||||||
showToast('Please enter something in the Search Bar.','error','warning');
|
el.addEventListener('click', function (e) {
|
||||||
return;
|
e.preventDefault();
|
||||||
}
|
focusFirstVisibleInput();
|
||||||
if (window.APP && typeof APP.handleSearch === 'function') {
|
});
|
||||||
APP.handleSearch(query);
|
});
|
||||||
if (input.id === 'searchInput') input.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleIndicatorAction(){
|
document.body.addEventListener('click', function (e) {
|
||||||
const inputs = getSearchInputs().filter(isVisible);
|
if (
|
||||||
const active = document.activeElement;
|
e.target.classList.contains('shortcut-indicator') ||
|
||||||
if (inputs.includes(active) && active.value.trim()) {
|
e.target.classList.contains('shortcut-indicator-2') ||
|
||||||
triggerSubmit(active);
|
e.target.classList.contains('shortcut-indicator-3') ||
|
||||||
return;
|
e.target.classList.contains('shortcut-indicator-4')
|
||||||
}
|
) {
|
||||||
const withText = inputs.find(i => i.value.trim());
|
e.preventDefault();
|
||||||
if (withText) {
|
focusFirstVisibleInput();
|
||||||
triggerSubmit(withText);
|
}
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
focusFirstVisibleInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateIndicatorState();
|
const coolIframe = document.getElementById('cool-iframe');
|
||||||
getSearchInputs().forEach(i => i.addEventListener('input', updateIndicatorState));
|
if (coolIframe) {
|
||||||
|
coolIframe.addEventListener('load', function () {
|
||||||
|
const doc = coolIframe.contentWindow.document;
|
||||||
|
|
||||||
document.addEventListener('keydown', e => {
|
doc.addEventListener('keydown', function (e) {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
const act = document.activeElement;
|
if (doc.activeElement && doc.activeElement.blur) {
|
||||||
if (getSearchInputs().includes(act)) {
|
doc.activeElement.blur();
|
||||||
act.blur();
|
e.preventDefault();
|
||||||
e.preventDefault();
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (e.ctrlKey && e.key.toLowerCase() === 's') {
|
if (e.ctrlKey && e.key.toLowerCase() === 's') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
focusFirstVisibleInput();
|
document.dispatchEvent(new KeyboardEvent('keydown', {
|
||||||
}
|
key: 's',
|
||||||
});
|
ctrlKey: true
|
||||||
|
}));
|
||||||
document.body.addEventListener('click', e => {
|
}
|
||||||
const ind = e.target.closest('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4');
|
|
||||||
if (!ind) return;
|
|
||||||
e.preventDefault();
|
|
||||||
if (ind.classList.contains('arrow-mode')) {
|
|
||||||
handleIndicatorAction();
|
|
||||||
} else {
|
|
||||||
focusFirstVisibleInput();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const coolIframe = document.getElementById('cool-iframe');
|
|
||||||
if (coolIframe){
|
|
||||||
coolIframe.addEventListener('load', () => {
|
|
||||||
const doc = coolIframe.contentWindow.document;
|
|
||||||
doc.addEventListener('keydown', innerE => {
|
|
||||||
if (innerE.key === 'Escape') {
|
|
||||||
if (doc.activeElement.blur) doc.activeElement.blur();
|
|
||||||
innerE.preventDefault();
|
|
||||||
}
|
|
||||||
if (innerE.ctrlKey && innerE.key.toLowerCase() === 's') {
|
|
||||||
innerE.preventDefault();
|
|
||||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 's', ctrlKey: true, bubbles: true }));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
doc.querySelectorAll('.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4')
|
|
||||||
.forEach(el => {
|
|
||||||
el.addEventListener('click', ev => {
|
|
||||||
ev.preventDefault();
|
|
||||||
window.parent.postMessage({ type: 'iframe-focus-search' }, '*');
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('message', msgEvt => {
|
doc.querySelectorAll(
|
||||||
if (msgEvt.data?.type === 'iframe-focus-search'){
|
'.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4'
|
||||||
const inp = focusFirstVisibleInput();
|
).forEach(function (iframeEl) {
|
||||||
if (inp && inp.value.trim()) triggerSubmit(inp);
|
iframeEl.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
window.parent.postMessage({
|
||||||
|
type: 'iframe-focus-search'
|
||||||
|
}, '*');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
});
|
window.addEventListener('message', function (event) {
|
||||||
|
const msg = event.data;
|
||||||
|
if (msg.type === 'iframe-focus-search') {
|
||||||
|
focusFirstVisibleInput();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
})();
|
})();
|
|
@ -1,59 +0,0 @@
|
||||||
(async()=>{
|
|
||||||
const storageKey = 'wv-verified';
|
|
||||||
const last = localStorage.getItem(storageKey);
|
|
||||||
if(last && Date.now() - last < 2592000000) return;
|
|
||||||
|
|
||||||
const style = document.createElement('style');
|
|
||||||
style.textContent = `
|
|
||||||
:root{--bg:#000;--card:rgba(0,0,0,0.85);--accent:#fff;--radius:12px;--trans:.3s}
|
|
||||||
#wv-overlay{position:fixed;inset:0!important;pointer-events:auto;user-select:none;background:var(--bg);display:flex;align-items:center;justify-content:center;font-family:system-ui;z-index:2147483647!important;opacity:1;transition:opacity .4s}
|
|
||||||
#wv-card{background:var(--card);backdrop-filter:blur(12px);border-radius:var(--radius);padding:32px;width:320px;text-align:center;color:var(--accent)}
|
|
||||||
#wv-progress{width:100%;height:6px;background:#333;border-radius:var(--radius);overflow:hidden;margin:16px 0}
|
|
||||||
#wv-bar{width:0;height:100%;background:var(--accent);transition:width var(--trans)}
|
|
||||||
#wv-info{font-size:.95rem;opacity:.8}
|
|
||||||
#wv-complete{display:none;}
|
|
||||||
#wv-complete.show{display:block;}
|
|
||||||
`;
|
|
||||||
document.head.appendChild(style);
|
|
||||||
|
|
||||||
const overlay = document.createElement('div'); overlay.id='wv-overlay';
|
|
||||||
overlay.innerHTML = `
|
|
||||||
<div id="wv-card">
|
|
||||||
<h2><i class="fas fa-shield-alt"></i> Verifying Browser</h2>
|
|
||||||
<div id="wv-progress"><div id="wv-bar"></div></div>
|
|
||||||
<div id="wv-info"></div>
|
|
||||||
</div>
|
|
||||||
<div id="wv-complete"><h2><i class="fas fa-check-circle"></i> Success!</h2><p>You May Continue.</p></div>
|
|
||||||
`;
|
|
||||||
document.body.appendChild(overlay);
|
|
||||||
|
|
||||||
const info = document.getElementById('wv-info');
|
|
||||||
const bar = document.getElementById('wv-bar');
|
|
||||||
const tests = [
|
|
||||||
{msg:'Automation',pass:!navigator.webdriver},
|
|
||||||
{msg:'Headless',pass:!/headless|phantomjs|puppeteer|selenium/i.test(navigator.userAgent)},
|
|
||||||
{msg:'Languages',pass:Array.isArray(navigator.languages) && navigator.languages.length>0},
|
|
||||||
{msg:'Plugins',pass:navigator.plugins.length>0},
|
|
||||||
{msg:'WebGL',pass:(()=>{try{const c=document.createElement('canvas');const g=c.getContext('webgl')||c.getContext('experimental-webgl');return!!g;}catch{return false;}})()}
|
|
||||||
];
|
|
||||||
|
|
||||||
let failures = [];
|
|
||||||
for(let i=0;i<tests.length;i++){
|
|
||||||
const t=tests[i];
|
|
||||||
info.textContent = `${t.msg}...`;
|
|
||||||
if(!t.pass) failures.push(t.msg);
|
|
||||||
bar.style.width = `${((i+1)/tests.length)*100}%`;
|
|
||||||
await new Promise(r=>setTimeout(r,200));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(failures.length===0){
|
|
||||||
localStorage.setItem(storageKey, Date.now());
|
|
||||||
document.getElementById('wv-card').style.display='none';
|
|
||||||
const done = document.getElementById('wv-complete'); done.classList.add('show');
|
|
||||||
setTimeout(()=>overlay.style.opacity='0',500);
|
|
||||||
setTimeout(()=>overlay.remove(),800);
|
|
||||||
} else {
|
|
||||||
info.innerHTML = `Failed:<br>${failures.map(f=>`• ${f}`).join('<br>')}`;
|
|
||||||
bar.style.background='red';
|
|
||||||
}
|
|
||||||
})();
|
|
31607
public/eagler.html
Normal file
31607
public/eagler.html
Normal file
File diff suppressed because one or more lines are too long
1
public/sw.js
Normal file
1
public/sw.js
Normal file
File diff suppressed because one or more lines are too long
1103
public/wah/cute2.js
1103
public/wah/cute2.js
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user