diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..993fee2
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,8 @@
+# Build artifacts
+dist/
+
+# Other things that don't need to be reformatted
+public/uv/
+public/dynamic/
+pnpm-lock.yaml
+package-lock.json
diff --git a/.prettierrc b/.prettierrc
index e902508..9a846d7 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,8 +1,8 @@
-{
- "singleQuote": false,
- "endOfLine": "crlf",
- "tabWidth": 2,
- "useTabs": false,
- "trailingComma": "none",
- "plugins": ["prettier-plugin-tailwindcss"]
-}
+{
+ "singleQuote": false,
+ "endOfLine": "crlf",
+ "tabWidth": 2,
+ "useTabs": false,
+ "trailingComma": "none",
+ "plugins": ["prettier-plugin-tailwindcss"]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ed78fd2..44a46f4 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,12 +1,12 @@
-{
- "editor.tabSize": 2,
- "editor.insertSpaces": true,
- "editor.formatOnSave": true,
- "editor.formatOnPaste": true,
- "editor.defaultFormatter": "esbenp.prettier-vscode",
- "files.autoSave": "afterDelay",
- "files.autoSaveDelay": 0,
- "css.lint.unknownAtRules": "ignore",
- "editor.linkedEditing": true,
- "css.lint.unknownProperties": "ignore"
-}
+{
+ "editor.tabSize": 2,
+ "editor.insertSpaces": true,
+ "editor.formatOnSave": true,
+ "editor.formatOnPaste": true,
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "files.autoSave": "afterDelay",
+ "files.autoSaveDelay": 0,
+ "css.lint.unknownAtRules": "ignore",
+ "editor.linkedEditing": true,
+ "css.lint.unknownProperties": "ignore"
+}
diff --git a/README.md b/README.md
index 452a49d..4886cec 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
-# Nebula rewrite
-`npm i -g pnpm tsx`
-`git clone https://github.com/NebulaServices/Nebula.git`
-`git switch rewrite`
-`pnpm i`
-
-readme meant for devs, will be changed before being merged into main
+# Nebula rewrite
+
+`npm i -g pnpm tsx`
+`git clone https://github.com/NebulaServices/Nebula.git`
+`git switch rewrite`
+`pnpm i`
+
+readme meant for devs, will be changed before being merged into main
diff --git a/framer-motion.d.ts b/framer-motion.d.ts
index b62fed5..44a8d8e 100644
--- a/framer-motion.d.ts
+++ b/framer-motion.d.ts
@@ -1,7 +1,7 @@
-import * as React from "preact/compat";
-
-declare module "framer-motion" {
- export interface AnimatePresenceProps {
- children?: React.ReactNode;
- }
-}
+import * as React from "preact/compat";
+
+declare module "framer-motion" {
+ export interface AnimatePresenceProps {
+ children?: React.ReactNode;
+ }
+}
diff --git a/index.html b/index.html
index 6603005..4a34c83 100644
--- a/index.html
+++ b/index.html
@@ -1,29 +1,29 @@
-
-
-
-
-
-
-
- Nebula
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ Nebula
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index 90f2215..840af3e 100644
--- a/package.json
+++ b/package.json
@@ -1,46 +1,46 @@
-{
- "private": true,
- "type": "module",
- "scripts": {
- "dev": "concurrently \"vite\" \"bare-server-node --port 8080\"",
- "build": "vite build",
- "bstart": "npm run build && tsx server.ts",
- "preview": "vite preview",
- "format": "prettier --write ."
- },
- "dependencies": {
- "@fastify/compress": "^6.5.0",
- "@fastify/static": "^6.12.0",
- "@titaniumnetwork-dev/ultraviolet": "^2.0.0",
- "@tomphttp/bare-server-node": "^2.0.1",
- "classnames": "^2.3.2",
- "fastify": "^4.25.1",
- "framer-motion": "^10.16.16",
- "i18next": "^23.7.9",
- "i18next-browser-languagedetector": "^7.2.0",
- "million": "^2.6.4",
- "preact": "^10.13.1",
- "preact-iso": "^2.3.2",
- "preact-render-to-string": "^6.3.1",
- "preact-router": "^4.1.2",
- "rammerhead": "https://github.com/holy-unblocker/rammerhead/releases/download/v1.2.41-holy.5/rammerhead-1.2.41-holy.5.tgz",
- "react-helmet": "^6.1.0",
- "react-i18next": "^13.5.0",
- "react-icons": "^4.12.0",
- "tsx": "^4.7.0"
- },
- "devDependencies": {
- "@preact/preset-vite": "^2.5.0",
- "autoprefixer": "^10.4.16",
- "concurrently": "^8.2.2",
- "eslint": "^8.55.0",
- "eslint-config-preact": "^1.3.0",
- "postcss": "^8.4.32",
- "prettier": "^3.1.1",
- "prettier-plugin-tailwindcss": "^0.5.9",
- "tailwindcss": "^3.3.6",
- "typescript": "^5.3.3",
- "vite": "^5.0.9",
- "vite-plugin-static-copy": "^1.0.0"
- }
-}
+{
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "concurrently \"vite\" \"bare-server-node --port 8080\"",
+ "build": "vite build",
+ "bstart": "npm run build && tsx server.ts",
+ "preview": "vite preview",
+ "format": "prettier --write ."
+ },
+ "dependencies": {
+ "@fastify/compress": "^6.5.0",
+ "@fastify/static": "^6.12.0",
+ "@titaniumnetwork-dev/ultraviolet": "^2.0.0",
+ "@tomphttp/bare-server-node": "^2.0.1",
+ "classnames": "^2.3.2",
+ "fastify": "^4.25.1",
+ "framer-motion": "^10.16.16",
+ "i18next": "^23.7.9",
+ "i18next-browser-languagedetector": "^7.2.0",
+ "million": "^2.6.4",
+ "preact": "^10.13.1",
+ "preact-iso": "^2.3.2",
+ "preact-render-to-string": "^6.3.1",
+ "preact-router": "^4.1.2",
+ "rammerhead": "https://github.com/holy-unblocker/rammerhead/releases/download/v1.2.41-holy.5/rammerhead-1.2.41-holy.5.tgz",
+ "react-helmet": "^6.1.0",
+ "react-i18next": "^13.5.0",
+ "react-icons": "^4.12.0",
+ "tsx": "^4.7.0"
+ },
+ "devDependencies": {
+ "@preact/preset-vite": "^2.5.0",
+ "autoprefixer": "^10.4.16",
+ "concurrently": "^8.2.2",
+ "eslint": "^8.55.0",
+ "eslint-config-preact": "^1.3.0",
+ "postcss": "^8.4.32",
+ "prettier": "^3.1.1",
+ "prettier-plugin-tailwindcss": "^0.5.9",
+ "tailwindcss": "^3.3.6",
+ "typescript": "^5.3.3",
+ "vite": "^5.0.9",
+ "vite-plugin-static-copy": "^1.0.0"
+ }
+}
diff --git a/postcss.config.js b/postcss.config.js
index ba80730..82fbe55 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -1,6 +1,6 @@
-export default {
- plugins: {
- tailwindcss: {},
- autoprefixer: {}
- }
-};
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {}
+ }
+};
diff --git a/public/dysw.js b/public/dysw.js
index ca32265..1159615 100644
--- a/public/dysw.js
+++ b/public/dysw.js
@@ -1,21 +1,21 @@
-importScripts("/dynamic/dynamic.config.js");
-importScripts("/dynamic/dynamic.worker.js");
-
-const dynamic = new Dynamic();
-
-self.dynamic = dynamic;
-
-self.addEventListener("fetch", (event) => {
- if (
- event.request.url.startsWith(location.origin + self.__dynamic$config.prefix)
- )
- event.respondWith(
- (async function () {
- if (await dynamic.route(event)) {
- return await dynamic.fetch(event);
- }
-
- return await fetch(event.request);
- })()
- );
-});
+importScripts("/dynamic/dynamic.config.js");
+importScripts("/dynamic/dynamic.worker.js");
+
+const dynamic = new Dynamic();
+
+self.dynamic = dynamic;
+
+self.addEventListener("fetch", (event) => {
+ if (
+ event.request.url.startsWith(location.origin + self.__dynamic$config.prefix)
+ )
+ event.respondWith(
+ (async function () {
+ if (await dynamic.route(event)) {
+ return await dynamic.fetch(event);
+ }
+
+ return await fetch(event.request);
+ })()
+ );
+});
diff --git a/public/uvsw.js b/public/uvsw.js
index d64cacc..ae7354b 100644
--- a/public/uvsw.js
+++ b/public/uvsw.js
@@ -1,10 +1,10 @@
-importScripts("/uv/uv.bundle.js");
-importScripts("/uv/uv.config.js");
-importScripts(__uv$config.sw || "/uv/uv.sw.js");
-
-const sw = new UVServiceWorker();
-
-self.addEventListener("fetch", (event) => {
- if (event.request.url.startsWith(location.origin + __uv$config.prefix))
- return event.respondWith(sw.fetch(event));
-});
+importScripts("/uv/uv.bundle.js");
+importScripts("/uv/uv.config.js");
+importScripts(__uv$config.sw || "/uv/uv.sw.js");
+
+const sw = new UVServiceWorker();
+
+self.addEventListener("fetch", (event) => {
+ if (event.request.url.startsWith(location.origin + __uv$config.prefix))
+ return event.respondWith(sw.fetch(event));
+});
diff --git a/server.ts b/server.ts
index b9fa1a9..a2c413e 100644
--- a/server.ts
+++ b/server.ts
@@ -1,86 +1,86 @@
-import fastify from 'fastify';
-import fastifyStatic from '@fastify/static';
-import { fileURLToPath } from 'url';
-import path from 'path';
-import createRammerhead from "rammerhead/src/server/index.js";
-import { createBareServer } from "@tomphttp/bare-server-node";
-import { createServer } from "http";
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-
-const bare = createBareServer("/bare/");
-const rh = createRammerhead();
-
-const rammerheadScopes = [
- "/rammerhead.js",
- "/hammerhead.js",
- "/transport-worker.js",
- "/task.js",
- "/iframe-task.js",
- "/worker-hammerhead.js",
- "/messaging",
- "/sessionexists",
- "/deletesession",
- "/newsession",
- "/editsession",
- "/needpassword",
- "/syncLocalStorage",
- "/api/shuffleDict",
- "/mainport"
-];
-
-const rammerheadSession = /^\/[a-z0-9]{32}/;
-
-function shouldRouteRh(req) {
- const url = new URL(req.url, "http://0.0.0.0");
- return (
- rammerheadScopes.includes(url.pathname) ||
- rammerheadSession.test(url.pathname)
- );
-}
-
-function routeRhRequest(req, res) {
- rh.emit("request", req, res);
-}
-
-function routeRhUpgrade(req, socket, head) {
- rh.emit("upgrade", req, socket, head);
-}
-
-const serverFactory = (handler, opts) => {
- return createServer()
- .on("request", (req, res) => {
- if (bare.shouldRoute(req)) {
- bare.routeRequest(req, res);
- } else if (shouldRouteRh(req)) {
- routeRhRequest(req, res);
- } else {
- handler(req, res);
- }
- })
- .on("upgrade", (req, socket, head) => {
- if (bare.shouldRoute(req)) {
- bare.routeUpgrade(req, socket, head);
- } else if (shouldRouteRh(req)) {
- routeRhUpgrade(req, socket, head);
- }
- });
-};
-
-const app = fastify({ logger: true, serverFactory });
-
-app.register(fastifyStatic, {
- root: path.join(__dirname, 'dist'),
- prefix: '/',
- serve: true,
- wildcard: false,
-});
-
-app.setNotFoundHandler((req, res) => {
- res.sendFile('index.html') // SPA catch-all
-})
-
-app.listen({
- port: 8080
-});
\ No newline at end of file
+import fastify from "fastify";
+import fastifyStatic from "@fastify/static";
+import { fileURLToPath } from "url";
+import path from "path";
+import createRammerhead from "rammerhead/src/server/index.js";
+import { createBareServer } from "@tomphttp/bare-server-node";
+import { createServer } from "http";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+const bare = createBareServer("/bare/");
+const rh = createRammerhead();
+
+const rammerheadScopes = [
+ "/rammerhead.js",
+ "/hammerhead.js",
+ "/transport-worker.js",
+ "/task.js",
+ "/iframe-task.js",
+ "/worker-hammerhead.js",
+ "/messaging",
+ "/sessionexists",
+ "/deletesession",
+ "/newsession",
+ "/editsession",
+ "/needpassword",
+ "/syncLocalStorage",
+ "/api/shuffleDict",
+ "/mainport"
+];
+
+const rammerheadSession = /^\/[a-z0-9]{32}/;
+
+function shouldRouteRh(req) {
+ const url = new URL(req.url, "http://0.0.0.0");
+ return (
+ rammerheadScopes.includes(url.pathname) ||
+ rammerheadSession.test(url.pathname)
+ );
+}
+
+function routeRhRequest(req, res) {
+ rh.emit("request", req, res);
+}
+
+function routeRhUpgrade(req, socket, head) {
+ rh.emit("upgrade", req, socket, head);
+}
+
+const serverFactory = (handler, opts) => {
+ return createServer()
+ .on("request", (req, res) => {
+ if (bare.shouldRoute(req)) {
+ bare.routeRequest(req, res);
+ } else if (shouldRouteRh(req)) {
+ routeRhRequest(req, res);
+ } else {
+ handler(req, res);
+ }
+ })
+ .on("upgrade", (req, socket, head) => {
+ if (bare.shouldRoute(req)) {
+ bare.routeUpgrade(req, socket, head);
+ } else if (shouldRouteRh(req)) {
+ routeRhUpgrade(req, socket, head);
+ }
+ });
+};
+
+const app = fastify({ logger: true, serverFactory });
+
+app.register(fastifyStatic, {
+ root: path.join(__dirname, "dist"),
+ prefix: "/",
+ serve: true,
+ wildcard: false
+});
+
+app.setNotFoundHandler((req, res) => {
+ res.sendFile("index.html"); // SPA catch-all
+});
+
+app.listen({
+ port: 8080
+});
diff --git a/src/components/HeaderRoute.tsx b/src/components/HeaderRoute.tsx
index 43fedec..989c129 100644
--- a/src/components/HeaderRoute.tsx
+++ b/src/components/HeaderRoute.tsx
@@ -1,12 +1,12 @@
-import { Header } from "./Header";
-
-export function HeaderRoute(props: { children: any }) {
- return (
-
-
-
- {props.children}
-
-
- );
-}
+import { Header } from "./Header";
+
+export function HeaderRoute(props: { children: any }) {
+ return (
+
+
+
+ {props.children}
+
+
+ );
+}
diff --git a/src/components/iframe/Iframe.tsx b/src/components/iframe/Iframe.tsx
index 4670203..735f828 100644
--- a/src/components/iframe/Iframe.tsx
+++ b/src/components/iframe/Iframe.tsx
@@ -1,13 +1,23 @@
-import { motion } from "framer-motion"
-import { IframeHeader } from "./IframeHeader"
-
-export function Iframe(props: { url: string }) {
- return (
- <>
-
-
-
-
- >
- )
-}
+import { motion } from "framer-motion";
+import { IframeHeader } from "./IframeHeader";
+
+export function Iframe(props: { url: string }) {
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
diff --git a/src/components/iframe/IframeHeader.tsx b/src/components/iframe/IframeHeader.tsx
index c6da442..442227d 100644
--- a/src/components/iframe/IframeHeader.tsx
+++ b/src/components/iframe/IframeHeader.tsx
@@ -1,33 +1,48 @@
-import { useState } from "preact/hooks";
-import { useTranslation } from "react-i18next";
-import { Link } from "preact-router";
-import { RiPictureInPictureExitFill, RiFullscreenFill } from "react-icons/ri"
-
-export function IframeHeader(props: { url: string }) {
- const { t } = useTranslation()
- const [showPopout, setShowPopout] = useState(false);
- const [showFullScreen, setFullScreen] = useState(false);
- if (showPopout) {
- window.location.replace(props.url);
- }
- if (showFullScreen) {
- document.getElementById("iframe").requestFullscreen();
- setFullScreen(false);
- }
- return (
-
-
-
-

-
{t("header.title")}
-
-
-
-
- setShowPopout(true)} />
- setFullScreen(true)} />
-
-
-
- )
-};
+import { useState } from "preact/hooks";
+import { useTranslation } from "react-i18next";
+import { Link } from "preact-router";
+import { RiPictureInPictureExitFill, RiFullscreenFill } from "react-icons/ri";
+
+export function IframeHeader(props: { url: string }) {
+ const { t } = useTranslation();
+ const [showPopout, setShowPopout] = useState(false);
+ const [showFullScreen, setFullScreen] = useState(false);
+ if (showPopout) {
+ window.location.replace(props.url);
+ }
+ if (showFullScreen) {
+ document.getElementById("iframe").requestFullscreen();
+ setFullScreen(false);
+ }
+ return (
+
+
+
+

+
+ {" "}
+ {t("header.title")}{" "}
+
+
+
+
+
+ setShowPopout(true)}
+ />
+ setFullScreen(true)}
+ />
+
+
+
+ );
+}
diff --git a/src/i18n.ts b/src/i18n.ts
index 0546094..5d82efb 100644
--- a/src/i18n.ts
+++ b/src/i18n.ts
@@ -1,32 +1,32 @@
-import i18n from "i18next";
-import { initReactI18next } from "react-i18next";
-import LanguageDetector from "i18next-browser-languagedetector";
-
-import translationEN from "./locales/en.json";
-import translationES from "./locales/es.json";
-import translationJA from "./locales/ja.json";
-
-const resources = {
- en: {
- translation: translationEN
- },
- es: {
- translation: translationES
- },
- ja: {
- translation: translationJA
- }
-};
-
-i18n
- .use(initReactI18next)
- .use(LanguageDetector)
- .init({
- resources,
- fallbackLng: "en",
- interpolation: {
- escapeValue: false
- }
- });
-
-export default i18n;
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
+import LanguageDetector from "i18next-browser-languagedetector";
+
+import translationEN from "./locales/en.json";
+import translationES from "./locales/es.json";
+import translationJA from "./locales/ja.json";
+
+const resources = {
+ en: {
+ translation: translationEN
+ },
+ es: {
+ translation: translationES
+ },
+ ja: {
+ translation: translationJA
+ }
+};
+
+i18n
+ .use(initReactI18next)
+ .use(LanguageDetector)
+ .init({
+ resources,
+ fallbackLng: "en",
+ interpolation: {
+ escapeValue: false
+ }
+ });
+
+export default i18n;
diff --git a/src/index.tsx b/src/index.tsx
index 931818c..eccc3b6 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,28 +1,27 @@
-import { render } from "preact";
-import { LocationProvider, Router, Route } from "preact-iso";
-import { Home } from "./pages/Home";
-import { NotFound } from "./pages/_404.jsx";
-import { DiscordPage } from "./pages/discord.jsx";
-import { ProxyFrame } from "./pages/ProxyFrame.js";
-import { Settings } from "./pages/Settings/index.js";
-
-import "./style.css";
-import "./themes/main.css";
-import "./i18n";
-
-export function App() {
- return (
-
-
-
-
-
-
-
-
-
- );
-}
-
-render(, document.getElementById("app"));
-
+import { render } from "preact";
+import { LocationProvider, Router, Route } from "preact-iso";
+import { Home } from "./pages/Home";
+import { NotFound } from "./pages/_404.jsx";
+import { DiscordPage } from "./pages/discord.jsx";
+import { ProxyFrame } from "./pages/ProxyFrame.js";
+import { Settings } from "./pages/Settings/index.js";
+
+import "./style.css";
+import "./themes/main.css";
+import "./i18n";
+
+export function App() {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+}
+
+render(, document.getElementById("app"));
diff --git a/src/locales/de.json b/src/locales/de.json
index 649bd77..78f194b 100644
--- a/src/locales/de.json
+++ b/src/locales/de.json
@@ -1,52 +1,52 @@
-{
- "header": {
- "title": "Nebel",
- "games": "Spiele",
- "settings": "einstellungen",
- "discord": "Sie wollen mehr URL-Adresse?"
- },
- "404": {
- "text": "Dieser Nebel-Dienst wurde deaktiviert.",
- "return": "Zurück nach Hause."
- },
- "home": {
- "placeholder": "Suchen Sie frei im Web."
- },
- "discord": {
- "title": "Nebel's Discord Server",
- "sub": "Möchten Sie diesen über einen Proxy öffnen?",
- "button1": "Normal öffnen",
- "button2": "Proxy verwenden"
- },
- "setting": {
- "tabs": {
- "proxy": "Proxy",
- "tab": "tab",
- "custom": "Anpassung",
- "misc": "Misc"
- },
- "proxy": {
- "title": "Proxy",
- "subtitle": "Wählen Sie den Proxy, der Ihren Anforderungen entspricht",
- "automatic": "Automatisch",
- "buggyWarning": "(PROBLEME)"
- },
- "languages": {
- "title": "Sprache",
- "subtitle": "Wählen Sie Ihre bevorzugte Sprache",
- "japanese": "Japanisch",
- "english": "Englisch",
- "spanish": "Spanisch",
- "german": "Deutsch",
- "greek": "Griechisch",
- "dutch": "Niederländisch"
- },
- "proxymodes": {
- "title": "Öffnen in",
- "subtitle": "Wählen Sie, wie Ihre Seiten geöffnet werden sollen",
- "embed": "Einbetten",
- "direct": "Direkt",
- "aboutblank": "About:Blank"
- }
- }
-}
+{
+ "header": {
+ "title": "Nebel",
+ "games": "Spiele",
+ "settings": "einstellungen",
+ "discord": "Sie wollen mehr URL-Adresse?"
+ },
+ "404": {
+ "text": "Dieser Nebel-Dienst wurde deaktiviert.",
+ "return": "Zurück nach Hause."
+ },
+ "home": {
+ "placeholder": "Suchen Sie frei im Web."
+ },
+ "discord": {
+ "title": "Nebel's Discord Server",
+ "sub": "Möchten Sie diesen über einen Proxy öffnen?",
+ "button1": "Normal öffnen",
+ "button2": "Proxy verwenden"
+ },
+ "setting": {
+ "tabs": {
+ "proxy": "Proxy",
+ "tab": "tab",
+ "custom": "Anpassung",
+ "misc": "Misc"
+ },
+ "proxy": {
+ "title": "Proxy",
+ "subtitle": "Wählen Sie den Proxy, der Ihren Anforderungen entspricht",
+ "automatic": "Automatisch",
+ "buggyWarning": "(PROBLEME)"
+ },
+ "languages": {
+ "title": "Sprache",
+ "subtitle": "Wählen Sie Ihre bevorzugte Sprache",
+ "japanese": "Japanisch",
+ "english": "Englisch",
+ "spanish": "Spanisch",
+ "german": "Deutsch",
+ "greek": "Griechisch",
+ "dutch": "Niederländisch"
+ },
+ "proxymodes": {
+ "title": "Öffnen in",
+ "subtitle": "Wählen Sie, wie Ihre Seiten geöffnet werden sollen",
+ "embed": "Einbetten",
+ "direct": "Direkt",
+ "aboutblank": "About:Blank"
+ }
+ }
+}
diff --git a/src/locales/en.json b/src/locales/en.json
index 2bb5837..0e6c2f9 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -1,52 +1,52 @@
-{
- "header": {
- "title": "nebula.",
- "games": "Games",
- "settings": "Settings",
- "discord": "Want more links?"
- },
- "404": {
- "text": "This Nebula Service has been disabled.",
- "return": "Back to home"
- },
- "home": {
- "placeholder": "Search the web freely"
- },
- "discord": {
- "title": "Nebula's Discord Server",
- "sub": "Would you like to open this via proxy?",
- "button1": "Open Normally",
- "button2": "Use Proxy"
- },
- "settings": {
- "tabs": {
- "proxy": "Proxy",
- "tab": "Tab",
- "custom": "Customization",
- "misc": "Misc"
- },
- "proxy": {
- "title": "Proxy",
- "subtitle": "Choose the proxy that fits your needs",
- "automatic": "Automatic",
- "buggyWarning": "(BUGGY)"
- },
- "languages": {
- "title": "Language",
- "subtitle": "Choose your preferred language",
- "japanese": "Japanese",
- "english": "English",
- "spanish": "Spanish",
- "german": "German",
- "greek": "Greek",
- "dutch": "Dutch"
- },
- "proxymodes": {
- "title": "Open in",
- "subtitle": "Choose how to open your sites",
- "embed": "Embed",
- "direct": "Direct",
- "aboutblank": "About:Blank"
- }
- }
-}
+{
+ "header": {
+ "title": "nebula.",
+ "games": "Games",
+ "settings": "Settings",
+ "discord": "Want more links?"
+ },
+ "404": {
+ "text": "This Nebula Service has been disabled.",
+ "return": "Back to home"
+ },
+ "home": {
+ "placeholder": "Search the web freely"
+ },
+ "discord": {
+ "title": "Nebula's Discord Server",
+ "sub": "Would you like to open this via proxy?",
+ "button1": "Open Normally",
+ "button2": "Use Proxy"
+ },
+ "settings": {
+ "tabs": {
+ "proxy": "Proxy",
+ "tab": "Tab",
+ "custom": "Customization",
+ "misc": "Misc"
+ },
+ "proxy": {
+ "title": "Proxy",
+ "subtitle": "Choose the proxy that fits your needs",
+ "automatic": "Automatic",
+ "buggyWarning": "(BUGGY)"
+ },
+ "languages": {
+ "title": "Language",
+ "subtitle": "Choose your preferred language",
+ "japanese": "Japanese",
+ "english": "English",
+ "spanish": "Spanish",
+ "german": "German",
+ "greek": "Greek",
+ "dutch": "Dutch"
+ },
+ "proxymodes": {
+ "title": "Open in",
+ "subtitle": "Choose how to open your sites",
+ "embed": "Embed",
+ "direct": "Direct",
+ "aboutblank": "About:Blank"
+ }
+ }
+}
diff --git a/src/locales/es.json b/src/locales/es.json
index 4f26d61..b696408 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -1,52 +1,52 @@
-{
- "header": {
- "title": "nebula.",
- "games": "Juegos",
- "settings": "Ajustes",
- "discord": "¿Quieres más enlaces?"
- },
- "404": {
- "text": "Este servicio Nebula ha sido deshabilitado.",
- "return": "De vuelta a casa"
- },
- "home": {
- "placeholder": "Busca en la web libremente"
- },
- "discord": {
- "title": "Nebula's Discord Servidor",
- "sub": "¿Le gustaría abrir esto a través de proxy?",
- "button1": "Abierto normalmente",
- "button2": "Usa proxy"
- },
- "settings": {
- "tabs": {
- "proxy": "Proxy",
- "tab": "Pestaña",
- "custom": "Personalización",
- "misc": "Misc"
- },
- "proxy": {
- "title": "Proxy",
- "subtitle": "Elige el proxy que se ajuste a tus necesidades",
- "automatic": "Automática",
- "buggyWarning": "(CALESA)"
- },
- "languages": {
- "title": "Idioma",
- "subtitle": "Elige tu idioma preferido",
- "japanese": "Japonés",
- "english": "Inglés",
- "spanish": "Español",
- "german": "",
- "greek": "",
- "dutch": ""
- },
- "proxymodes": {
- "title": "Abrir en",
- "subtitle": "Elige cómo abrir tus sitios",
- "embed": "Incrustar",
- "direct": "Directo",
- "aboutblank": "About:Blank"
- }
- }
-}
+{
+ "header": {
+ "title": "nebula.",
+ "games": "Juegos",
+ "settings": "Ajustes",
+ "discord": "¿Quieres más enlaces?"
+ },
+ "404": {
+ "text": "Este servicio Nebula ha sido deshabilitado.",
+ "return": "De vuelta a casa"
+ },
+ "home": {
+ "placeholder": "Busca en la web libremente"
+ },
+ "discord": {
+ "title": "Nebula's Discord Servidor",
+ "sub": "¿Le gustaría abrir esto a través de proxy?",
+ "button1": "Abierto normalmente",
+ "button2": "Usa proxy"
+ },
+ "settings": {
+ "tabs": {
+ "proxy": "Proxy",
+ "tab": "Pestaña",
+ "custom": "Personalización",
+ "misc": "Misc"
+ },
+ "proxy": {
+ "title": "Proxy",
+ "subtitle": "Elige el proxy que se ajuste a tus necesidades",
+ "automatic": "Automática",
+ "buggyWarning": "(CALESA)"
+ },
+ "languages": {
+ "title": "Idioma",
+ "subtitle": "Elige tu idioma preferido",
+ "japanese": "Japonés",
+ "english": "Inglés",
+ "spanish": "Español",
+ "german": "",
+ "greek": "",
+ "dutch": ""
+ },
+ "proxymodes": {
+ "title": "Abrir en",
+ "subtitle": "Elige cómo abrir tus sitios",
+ "embed": "Incrustar",
+ "direct": "Directo",
+ "aboutblank": "About:Blank"
+ }
+ }
+}
diff --git a/src/locales/gr.json b/src/locales/gr.json
index 66c6eb1..8b6f2d3 100644
--- a/src/locales/gr.json
+++ b/src/locales/gr.json
@@ -1,52 +1,52 @@
-{
- "header": {
- "title": "νεφέλωμα",
- "games": "Παιχνίδια",
- "settings": "Ρυθμίσεις",
- "discord": "θέλετε περισσότερους συνδέσμους?"
- },
- "404": {
- "text": "Αυτή η υπηρεσία Νεφέλωμα έχει απενεργοποιηθεί.",
- "return": "Επιστροφή στο σπίτι."
- },
- "home": {
- "placeholder": "Ελεύθερη αναζήτηση στο διαδίκτυο."
- },
- "discord": {
- "title": "Discord Διακομιστής του Νεφελώματος",
- "sub": "Άνοιγμα μέσω διακομιστή μεσολάβησης;",
- "button1": "Ανοιχτό κανονικά",
- "button2": "Χρήση μεσολάβησης"
- },
- "setting": {
- "tabs": {
- "proxy": "Mεσολάβησης",
- "tab": "Καρτέλα",
- "custom": "Προσαρμογή",
- "misc": "Διάφορα"
- },
- "proxy": {
- "title": "Μεσολάβηση",
- "subtitle": "Επιλέξτε τη μεσολάβηση που ταιριάζει στις ανάγκες σας",
- "automatic": "Αυτόματο",
- "buggyWarning": "(ΠΡΟΒΛΗΜΑ)"
- },
- "languages": {
- "title": "Γλώσσες",
- "subtitle": "Επιλέξτε τη γλώσσα που προτιμάτε",
- "japanese": "Ιαπωνικά",
- "english": "Αγγλικά",
- "spanish": "Ησπανικά",
- "german": "Γερμανικό",
- "greek": "Ελληνικά",
- "dutch": "Ολλανδικά"
- },
- "proxymodes": {
- "title": "Άνοιγμα σε",
- "subtitle": "Επιλέξτε τον τρόπο ανοίγματος των ιστοσελίδων σας",
- "embed": "εΕνσωμάτωση",
- "direct": "¨Αμεσα",
- "aboutblank": "About:Blank"
- }
- }
-}
+{
+ "header": {
+ "title": "νεφέλωμα",
+ "games": "Παιχνίδια",
+ "settings": "Ρυθμίσεις",
+ "discord": "θέλετε περισσότερους συνδέσμους?"
+ },
+ "404": {
+ "text": "Αυτή η υπηρεσία Νεφέλωμα έχει απενεργοποιηθεί.",
+ "return": "Επιστροφή στο σπίτι."
+ },
+ "home": {
+ "placeholder": "Ελεύθερη αναζήτηση στο διαδίκτυο."
+ },
+ "discord": {
+ "title": "Discord Διακομιστής του Νεφελώματος",
+ "sub": "Άνοιγμα μέσω διακομιστή μεσολάβησης;",
+ "button1": "Ανοιχτό κανονικά",
+ "button2": "Χρήση μεσολάβησης"
+ },
+ "setting": {
+ "tabs": {
+ "proxy": "Mεσολάβησης",
+ "tab": "Καρτέλα",
+ "custom": "Προσαρμογή",
+ "misc": "Διάφορα"
+ },
+ "proxy": {
+ "title": "Μεσολάβηση",
+ "subtitle": "Επιλέξτε τη μεσολάβηση που ταιριάζει στις ανάγκες σας",
+ "automatic": "Αυτόματο",
+ "buggyWarning": "(ΠΡΟΒΛΗΜΑ)"
+ },
+ "languages": {
+ "title": "Γλώσσες",
+ "subtitle": "Επιλέξτε τη γλώσσα που προτιμάτε",
+ "japanese": "Ιαπωνικά",
+ "english": "Αγγλικά",
+ "spanish": "Ησπανικά",
+ "german": "Γερμανικό",
+ "greek": "Ελληνικά",
+ "dutch": "Ολλανδικά"
+ },
+ "proxymodes": {
+ "title": "Άνοιγμα σε",
+ "subtitle": "Επιλέξτε τον τρόπο ανοίγματος των ιστοσελίδων σας",
+ "embed": "εΕνσωμάτωση",
+ "direct": "¨Αμεσα",
+ "aboutblank": "About:Blank"
+ }
+ }
+}
diff --git a/src/locales/ja.json b/src/locales/ja.json
index 3c87114..992d5f8 100644
--- a/src/locales/ja.json
+++ b/src/locales/ja.json
@@ -1,52 +1,52 @@
-{
- "header": {
- "title": "ネブラ。",
- "games": "ゲーム",
- "settings": "セッティング",
- "discord": "もっとリンクが欲しいですか?"
- },
- "404": {
- "text": "このネブラサービスは無効になっています",
- "return": "帰宅"
- },
- "home": {
- "placeholder": "由にウェブを検索"
- },
- "discord": {
- "title": "ネブラDiscordサーバー",
- "sub": "プロキシ経由で開きますか?",
- "button1": "通常通り開く",
- "button2": "プロキシを使用する"
- },
- "settings": {
- "tabs": {
- "proxy": "プロキシ",
- "tab": "タブ",
- "custom": "カスタマイズ",
- "misc": "その他"
- },
- "proxy": {
- "title": "プロキシ",
- "subtitle": "ニーズに合ったプロキシを選んでください",
- "automatic": "自動",
- "buggyWarning": "(バグ)"
- },
- "languages": {
- "title": "言語",
- "subtitle": "好きな言語を選んでください",
- "japanese": "日本語",
- "english": "英語",
- "spanish": "スペイン語",
- "german": "",
- "greek": "",
- "dutch": ""
- },
- "proxymodes": {
- "title": "開く",
- "subtitle": "サイトを開く方法を選択する",
- "embed": "埋め込む",
- "direct": "直接",
- "aboutblank": "About:Blank"
- }
- }
-}
+{
+ "header": {
+ "title": "ネブラ。",
+ "games": "ゲーム",
+ "settings": "セッティング",
+ "discord": "もっとリンクが欲しいですか?"
+ },
+ "404": {
+ "text": "このネブラサービスは無効になっています",
+ "return": "帰宅"
+ },
+ "home": {
+ "placeholder": "由にウェブを検索"
+ },
+ "discord": {
+ "title": "ネブラDiscordサーバー",
+ "sub": "プロキシ経由で開きますか?",
+ "button1": "通常通り開く",
+ "button2": "プロキシを使用する"
+ },
+ "settings": {
+ "tabs": {
+ "proxy": "プロキシ",
+ "tab": "タブ",
+ "custom": "カスタマイズ",
+ "misc": "その他"
+ },
+ "proxy": {
+ "title": "プロキシ",
+ "subtitle": "ニーズに合ったプロキシを選んでください",
+ "automatic": "自動",
+ "buggyWarning": "(バグ)"
+ },
+ "languages": {
+ "title": "言語",
+ "subtitle": "好きな言語を選んでください",
+ "japanese": "日本語",
+ "english": "英語",
+ "spanish": "スペイン語",
+ "german": "",
+ "greek": "",
+ "dutch": ""
+ },
+ "proxymodes": {
+ "title": "開く",
+ "subtitle": "サイトを開く方法を選択する",
+ "embed": "埋め込む",
+ "direct": "直接",
+ "aboutblank": "About:Blank"
+ }
+ }
+}
diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx
index 3b8d6a4..d4f2259 100644
--- a/src/pages/Home.tsx
+++ b/src/pages/Home.tsx
@@ -1,55 +1,55 @@
-import { useState } from "preact/hooks";
-import { useTranslation } from "react-i18next";
-import { HeaderRoute } from "../components/HeaderRoute";
-import { Helmet } from "react-helmet";
-
-export function Home() {
- const [isFocused, setIsFocused] = useState(false);
- const [inputValue, setInputValue] = useState("");
- const { t } = useTranslation();
-
- const handleSubmit = (event) => {
- event.preventDefault();
- window.location.href = "/go/" + encodeURIComponent(inputValue);
- };
-
- return (
-
-
- Nebula
-
-
-
- Nebula © Nebula Services {new Date().getUTCFullYear()}
-
-
-
- GitHub
-
-
-
-
-
- );
-}
+import { useState } from "preact/hooks";
+import { useTranslation } from "react-i18next";
+import { HeaderRoute } from "../components/HeaderRoute";
+import { Helmet } from "react-helmet";
+
+export function Home() {
+ const [isFocused, setIsFocused] = useState(false);
+ const [inputValue, setInputValue] = useState("");
+ const { t } = useTranslation();
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ window.location.href = "/go/" + encodeURIComponent(inputValue);
+ };
+
+ return (
+
+
+ Nebula
+
+
+
+ Nebula © Nebula Services {new Date().getUTCFullYear()}
+
+
+
+ GitHub
+
+
+
+
+
+ );
+}
diff --git a/src/pages/ProxyFrame.tsx b/src/pages/ProxyFrame.tsx
index 45906d6..4d84287 100644
--- a/src/pages/ProxyFrame.tsx
+++ b/src/pages/ProxyFrame.tsx
@@ -1,84 +1,85 @@
-import { RammerheadEncode } from "../util/RammerheadEncode";
-import { searchUtil } from "../util/searchUtil";
-import { useEffect, useState } from "preact/hooks";
-//import our Iframe component
-import { Iframe } from "../components/iframe/Iframe";
-
-declare global {
- interface Window {
- __uv$config: any;
- __dynamic$config: any;
- }
-}
-
-export function ProxyFrame(props: { url: string }) {
- // pass the URL encoded with encodeURIcomponent
- const localProxy = localStorage.getItem("proxy") || "automatic";
- const proxyMode = localStorage.getItem("proxyMode") || "direct";
-
- const [ProxiedUrl, setProxiedUrl] = useState(undefined);
-
- let decodedUrl = decodeURIComponent(props.url);
- //attempt to convert to a valid url
- decodedUrl = searchUtil(decodedUrl, "https://google.com/search?q=%s");
-
- let proxyRef;
-
- useEffect(() => {
- // For now we can redirect to the results. In the future we will add an if statement looking for the users proxy display choice
- if (localProxy === "rammerhead") {
- RammerheadEncode(decodedUrl).then((result: string) => {
- setProxiedUrl(result);
- });
- } else if (localProxy === "ultraviolet") {
- setProxiedUrl(
- window.__uv$config.prefix + window.__uv$config.encodeUrl(decodedUrl)
- );
- } else if (localProxy === "dynamic") {
- setProxiedUrl(
- window.__dynamic$config.prefix + encodeURIComponent(decodedUrl)
- );
- } else {
- // use UV for automatic
- setProxiedUrl(
- window.__uv$config.prefix + window.__uv$config.encodeUrl(decodedUrl)
- );
- }
- }, [localProxy]);
-
- if (proxyMode == "direct") {
- window.location.href = ProxiedUrl;
- }
- else if (proxyMode == "aboutblank") {
- const newWindow = window.open("about:blank", "_blank");
- const newDocument = newWindow.document.open();
- newDocument.write(`
-
-
-
-
-
-
-
-
-
- `);
- newDocument.close()
- window.location.replace("/");
- }
-
- return (
-
- {proxyMode === "direct" &&
Loading {localProxy}...
}
- {proxyMode === "aboutblank" && Loading {localProxy}...
}
- {proxyMode === "embed" && }
-
- );
-}
+import { RammerheadEncode } from "../util/RammerheadEncode";
+import { searchUtil } from "../util/searchUtil";
+import { useEffect, useState } from "preact/hooks";
+//import our Iframe component
+import { Iframe } from "../components/iframe/Iframe";
+
+declare global {
+ interface Window {
+ __uv$config: any;
+ __dynamic$config: any;
+ }
+}
+
+export function ProxyFrame(props: { url: string }) {
+ // pass the URL encoded with encodeURIcomponent
+ const localProxy = localStorage.getItem("proxy") || "automatic";
+ const proxyMode = localStorage.getItem("proxyMode") || "direct";
+
+ const [ProxiedUrl, setProxiedUrl] = useState(undefined);
+
+ let decodedUrl = decodeURIComponent(props.url);
+ //attempt to convert to a valid url
+ decodedUrl = searchUtil(decodedUrl, "https://google.com/search?q=%s");
+
+ let proxyRef;
+
+ useEffect(() => {
+ // For now we can redirect to the results. In the future we will add an if statement looking for the users proxy display choice
+ if (localProxy === "rammerhead") {
+ RammerheadEncode(decodedUrl).then((result: string) => {
+ setProxiedUrl(result);
+ });
+ } else if (localProxy === "ultraviolet") {
+ setProxiedUrl(
+ window.__uv$config.prefix + window.__uv$config.encodeUrl(decodedUrl)
+ );
+ } else if (localProxy === "dynamic") {
+ setProxiedUrl(
+ window.__dynamic$config.prefix + encodeURIComponent(decodedUrl)
+ );
+ } else {
+ // use UV for automatic
+ setProxiedUrl(
+ window.__uv$config.prefix + window.__uv$config.encodeUrl(decodedUrl)
+ );
+ }
+ }, [localProxy]);
+
+ if (proxyMode == "direct") {
+ window.location.href = ProxiedUrl;
+ } else if (proxyMode == "aboutblank") {
+ const newWindow = window.open("about:blank", "_blank");
+ const newDocument = newWindow.document.open();
+ newDocument.write(`
+
+
+
+
+
+
+
+
+
+ `);
+ newDocument.close();
+ window.location.replace("/");
+ }
+
+ return (
+
+ {proxyMode === "direct" &&
Loading {localProxy}...
}
+ {proxyMode === "aboutblank" && Loading {localProxy}...
}
+ {proxyMode === "embed" && (
+
+ )}
+
+ );
+}
diff --git a/src/pages/Settings/Customization.tsx b/src/pages/Settings/Customization.tsx
index 8abb51f..843f101 100644
--- a/src/pages/Settings/Customization.tsx
+++ b/src/pages/Settings/Customization.tsx
@@ -1,19 +1,19 @@
-import { motion } from "framer-motion";
-import { tabContentVariant, settingsPageVariant } from "./Variants";
-
-const Customization = ({ id, active }) => (
-
-
- Customization
-
-
-);
-
-export default Customization;
+import { motion } from "framer-motion";
+import { tabContentVariant, settingsPageVariant } from "./Variants";
+
+const Customization = ({ id, active }) => (
+
+
+ Customization
+
+
+);
+
+export default Customization;
diff --git a/src/pages/Settings/Dropdown.tsx b/src/pages/Settings/Dropdown.tsx
index 0b8fa84..1e92425 100644
--- a/src/pages/Settings/Dropdown.tsx
+++ b/src/pages/Settings/Dropdown.tsx
@@ -1,73 +1,73 @@
-import { useState, useEffect } from "preact/hooks";
-import { FaAngleDown } from "react-icons/fa";
-
-interface Option {
- id: string;
- label: string; // Translations CAN be passed
-}
-
-const Dropdown = ({
- storageKey,
- options,
- refresh
-}: {
- storageKey: string;
- options: Option[];
- refresh: boolean;
-}) => {
- const [isOpen, setIsOpen] = useState(false);
-
- const [choice, setChoice] = useState(() => {
- return localStorage.getItem(storageKey) || options[0]?.id || "";
- });
-
- // update on localstorage change
- useEffect(() => {
- setChoice(localStorage.getItem(storageKey) || options[0]?.id || "");
- }, [storageKey, options]);
-
- return (
-
-
setIsOpen(!isOpen)}
- >
-
-
-
- {options.find((o) => o.id === choice)?.label}
-
-
-
-
-
- {isOpen && (
-
- {options.map((option, index) => (
-
{
- setIsOpen(false);
- setChoice(option.id);
- localStorage.setItem(storageKey, option.id);
- if (refresh === true) {
- window.location.reload();
- }
- }}
- >
- {option.label}
-
- ))}
-
- )}
-
-
- );
-};
-
-export default Dropdown;
+import { useState, useEffect } from "preact/hooks";
+import { FaAngleDown } from "react-icons/fa";
+
+interface Option {
+ id: string;
+ label: string; // Translations CAN be passed
+}
+
+const Dropdown = ({
+ storageKey,
+ options,
+ refresh
+}: {
+ storageKey: string;
+ options: Option[];
+ refresh: boolean;
+}) => {
+ const [isOpen, setIsOpen] = useState(false);
+
+ const [choice, setChoice] = useState(() => {
+ return localStorage.getItem(storageKey) || options[0]?.id || "";
+ });
+
+ // update on localstorage change
+ useEffect(() => {
+ setChoice(localStorage.getItem(storageKey) || options[0]?.id || "");
+ }, [storageKey, options]);
+
+ return (
+
+
setIsOpen(!isOpen)}
+ >
+
+
+
+ {options.find((o) => o.id === choice)?.label}
+
+
+
+
+
+ {isOpen && (
+
+ {options.map((option, index) => (
+
{
+ setIsOpen(false);
+ setChoice(option.id);
+ localStorage.setItem(storageKey, option.id);
+ if (refresh === true) {
+ window.location.reload();
+ }
+ }}
+ >
+ {option.label}
+
+ ))}
+
+ )}
+
+
+ );
+};
+
+export default Dropdown;
diff --git a/src/pages/Settings/Misc.tsx b/src/pages/Settings/Misc.tsx
index 6bc1a22..84412de 100644
--- a/src/pages/Settings/Misc.tsx
+++ b/src/pages/Settings/Misc.tsx
@@ -1,41 +1,41 @@
-import { motion } from "framer-motion";
-import { tabContentVariant, settingsPageVariant } from "./Variants";
-import Dropdown from "./Dropdown";
-import { useTranslation } from "react-i18next";
-
-const Misc = ({ id, active }) => {
- const { t } = useTranslation();
-
- const languages = [
- { id: "en-US", label: t("settings.languages.english") },
- { id: "es", label: t("settings.languages.spanish") },
- { id: "ja", label: t("settings.languages.japanese") }
- ];
-
- return (
-
-
-
-
{t("settings.languages.title")}
-
{t("settings.languages.subtitle")}
-
-
-
-
- );
-};
-export default Misc;
+import { motion } from "framer-motion";
+import { tabContentVariant, settingsPageVariant } from "./Variants";
+import Dropdown from "./Dropdown";
+import { useTranslation } from "react-i18next";
+
+const Misc = ({ id, active }) => {
+ const { t } = useTranslation();
+
+ const languages = [
+ { id: "en-US", label: t("settings.languages.english") },
+ { id: "es", label: t("settings.languages.spanish") },
+ { id: "ja", label: t("settings.languages.japanese") }
+ ];
+
+ return (
+
+
+
+
{t("settings.languages.title")}
+
{t("settings.languages.subtitle")}
+
+
+
+
+ );
+};
+export default Misc;
diff --git a/src/pages/Settings/Proxy.tsx b/src/pages/Settings/Proxy.tsx
index bb9604b..14dd4b6 100644
--- a/src/pages/Settings/Proxy.tsx
+++ b/src/pages/Settings/Proxy.tsx
@@ -1,49 +1,53 @@
-import { motion } from "framer-motion";
-import { tabContentVariant, settingsPageVariant } from "./Variants";
-import Dropdown from "./Dropdown";
-import { useTranslation } from "react-i18next";
-
-const Proxy = ({ id, active }) => {
- const { t } = useTranslation();
-
- const engines = [
- { id: "automatic", label: t("settings.proxy.automatic") },
- { id: "ultraviolet", label: "Ultraviolet" },
- { id: "rammerhead", label: "Rammerhead" },
- { id: "dynamic", label: "Dynamic " + t("settings.proxy.buggyWarning") }
- ];
-
- const proxyModes = [
- { id: "direct", label: t("settings.proxymodes.direct") },
- { id: "embed", label: t("settings.proxymodes.embed") },
- { id: "aboutblank", label: t("settings.proxymodes.aboutblank") }
- ];
-
- return (
-
-
-
-
{t("settings.proxy.title")}
-
{t("settings.proxy.subtitle")}
-
-
-
-
{t("settings.proxymodes.title")}
-
{t("settings.proxymodes.subtitle")}
-
-
-
-
- );
-};
-export default Proxy;
+import { motion } from "framer-motion";
+import { tabContentVariant, settingsPageVariant } from "./Variants";
+import Dropdown from "./Dropdown";
+import { useTranslation } from "react-i18next";
+
+const Proxy = ({ id, active }) => {
+ const { t } = useTranslation();
+
+ const engines = [
+ { id: "automatic", label: t("settings.proxy.automatic") },
+ { id: "ultraviolet", label: "Ultraviolet" },
+ { id: "rammerhead", label: "Rammerhead" },
+ { id: "dynamic", label: "Dynamic " + t("settings.proxy.buggyWarning") }
+ ];
+
+ const proxyModes = [
+ { id: "direct", label: t("settings.proxymodes.direct") },
+ { id: "embed", label: t("settings.proxymodes.embed") },
+ { id: "aboutblank", label: t("settings.proxymodes.aboutblank") }
+ ];
+
+ return (
+
+
+
+
{t("settings.proxy.title")}
+
{t("settings.proxy.subtitle")}
+
+
+
+
{t("settings.proxymodes.title")}
+
{t("settings.proxymodes.subtitle")}
+
+
+
+
+ );
+};
+export default Proxy;
diff --git a/src/pages/Settings/TabComponent.tsx b/src/pages/Settings/TabComponent.tsx
index 7796258..ded1845 100644
--- a/src/pages/Settings/TabComponent.tsx
+++ b/src/pages/Settings/TabComponent.tsx
@@ -1,106 +1,106 @@
-import { useState, useEffect } from "preact/hooks";
-import cn from "classnames";
-import { motion } from "framer-motion";
-import "./styles.css";
-import { useTranslation } from "react-i18next";
-
-const tabVariant = {
- active: {
- width: "55%",
- transition: {
- type: "tween",
- duration: 0.4
- }
- },
- inactive: {
- width: "15%",
- transition: {
- type: "tween",
- duration: 0.4
- }
- }
-};
-
-const tabTextVariant = {
- active: {
- opacity: 1,
- x: 0,
- display: "block",
- transition: {
- type: "tween",
- duration: 0.3,
- delay: 0.3
- }
- },
- inactive: {
- opacity: 0,
- x: -30,
- transition: {
- type: "tween",
- duration: 0.3,
- delay: 0.1
- },
- transitionEnd: { display: "none" }
- }
-};
-
-const TabComponent = ({ tabs, defaultIndex = 0 }) => {
- const [activeTabIndex, setActiveTabIndex] = useState(defaultIndex);
-
- useEffect(() => {
- document.documentElement.style.setProperty(
- "--active-color",
- tabs[activeTabIndex].color
- );
- }, [activeTabIndex, tabs]);
-
- // Default to a tab based on the URL hash value
- useEffect(() => {
- const tabFromHash = tabs.findIndex(
- (tab) => `#${tab.id}` === window.location.hash
- );
- setActiveTabIndex(tabFromHash !== -1 ? tabFromHash : defaultIndex);
- }, [tabs, defaultIndex]);
-
- const onTabClick = (index) => {
- setActiveTabIndex(index);
- };
-
- const { t } = useTranslation()
-
- return (
-
-
-
-
- {tabs.map((tab, index) => (
-
- ))}
-
-
-
- );
-};
-
-export default TabComponent;
+import { useState, useEffect } from "preact/hooks";
+import cn from "classnames";
+import { motion } from "framer-motion";
+import "./styles.css";
+import { useTranslation } from "react-i18next";
+
+const tabVariant = {
+ active: {
+ width: "55%",
+ transition: {
+ type: "tween",
+ duration: 0.4
+ }
+ },
+ inactive: {
+ width: "15%",
+ transition: {
+ type: "tween",
+ duration: 0.4
+ }
+ }
+};
+
+const tabTextVariant = {
+ active: {
+ opacity: 1,
+ x: 0,
+ display: "block",
+ transition: {
+ type: "tween",
+ duration: 0.3,
+ delay: 0.3
+ }
+ },
+ inactive: {
+ opacity: 0,
+ x: -30,
+ transition: {
+ type: "tween",
+ duration: 0.3,
+ delay: 0.1
+ },
+ transitionEnd: { display: "none" }
+ }
+};
+
+const TabComponent = ({ tabs, defaultIndex = 0 }) => {
+ const [activeTabIndex, setActiveTabIndex] = useState(defaultIndex);
+
+ useEffect(() => {
+ document.documentElement.style.setProperty(
+ "--active-color",
+ tabs[activeTabIndex].color
+ );
+ }, [activeTabIndex, tabs]);
+
+ // Default to a tab based on the URL hash value
+ useEffect(() => {
+ const tabFromHash = tabs.findIndex(
+ (tab) => `#${tab.id}` === window.location.hash
+ );
+ setActiveTabIndex(tabFromHash !== -1 ? tabFromHash : defaultIndex);
+ }, [tabs, defaultIndex]);
+
+ const onTabClick = (index) => {
+ setActiveTabIndex(index);
+ };
+
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+ {tabs.map((tab, index) => (
+
+ ))}
+
+
+
+ );
+};
+
+export default TabComponent;
diff --git a/src/pages/Settings/TabSettings.tsx b/src/pages/Settings/TabSettings.tsx
index bb5d31e..a7ae9a3 100644
--- a/src/pages/Settings/TabSettings.tsx
+++ b/src/pages/Settings/TabSettings.tsx
@@ -1,19 +1,19 @@
-import { motion } from "framer-motion";
-import { tabContentVariant, settingsPageVariant } from "./Variants";
-
-const TabSettings = ({ id, active }) => (
-
-
- Tab settings
-
-
-);
-
-export default TabSettings;
+import { motion } from "framer-motion";
+import { tabContentVariant, settingsPageVariant } from "./Variants";
+
+const TabSettings = ({ id, active }) => (
+
+
+ Tab settings
+
+
+);
+
+export default TabSettings;
diff --git a/src/pages/Settings/Variants.tsx b/src/pages/Settings/Variants.tsx
index 0a29d6a..37f0b84 100644
--- a/src/pages/Settings/Variants.tsx
+++ b/src/pages/Settings/Variants.tsx
@@ -1,30 +1,30 @@
-const tabContentVariant = {
- active: {
- display: "block",
- transition: {
- staggerChildren: 0.2
- }
- },
- inactive: {
- display: "none"
- }
-};
-
-const settingsPageVariant = {
- active: {
- opacity: 1,
- y: 0,
- transition: {
- duration: 0.5
- }
- },
- inactive: {
- opacity: 0,
- y: 10,
- transition: {
- duration: 0.5
- }
- }
-};
-
-export { settingsPageVariant, tabContentVariant };
+const tabContentVariant = {
+ active: {
+ display: "block",
+ transition: {
+ staggerChildren: 0.2
+ }
+ },
+ inactive: {
+ display: "none"
+ }
+};
+
+const settingsPageVariant = {
+ active: {
+ opacity: 1,
+ y: 0,
+ transition: {
+ duration: 0.5
+ }
+ },
+ inactive: {
+ opacity: 0,
+ y: 10,
+ transition: {
+ duration: 0.5
+ }
+ }
+};
+
+export { settingsPageVariant, tabContentVariant };
diff --git a/src/pages/Settings/index.tsx b/src/pages/Settings/index.tsx
index 87b10a0..1befedc 100644
--- a/src/pages/Settings/index.tsx
+++ b/src/pages/Settings/index.tsx
@@ -1,15 +1,15 @@
-import TabComponent from "./TabComponent";
-import { HeaderRoute } from "../../components/HeaderRoute";
-import tabs from "./tabs";
-import { Helmet } from "react-helmet"
-
-export function Settings() {
- return (
-
-
- Settings
-
-
-
- );
-}
+import TabComponent from "./TabComponent";
+import { HeaderRoute } from "../../components/HeaderRoute";
+import tabs from "./tabs";
+import { Helmet } from "react-helmet";
+
+export function Settings() {
+ return (
+
+
+ Settings
+
+
+
+ );
+}
diff --git a/src/pages/Settings/styles.css b/src/pages/Settings/styles.css
index 68e761c..662c3b8 100644
--- a/src/pages/Settings/styles.css
+++ b/src/pages/Settings/styles.css
@@ -1,128 +1,128 @@
-* {
- box-sizing: border-box;
-}
-
-:root {
- --white: #fff;
- --black: #333;
- --active-color: #f1f1f1;
- --border-radius: 40px;
-}
-
-body {
- -webkit-font-smoothing: antialiased;
- font-family: Arial, Helvetica, sans-serif;
- background: var(--active-color);
- transition: background 1.5s ease;
-}
-
-img {
- max-width: 100%;
- vertical-align: middle;
-}
-
-.tabs-component {
- width: 100%;
- height: 100%;
- margin: auto;
- padding: 40px;
- border-radius: var(--border-radius);
-}
-
-.tab-links {
- padding: 0;
- margin: 0 auto 20px;
- list-style: none;
- max-width: 400px;
- display: flex;
- justify-content: space-between;
-}
-
-.tab {
- position: relative;
-}
-
-.tab a {
- text-decoration: none;
- color: var(--black);
-}
-
-.tab::before {
- content: "";
- width: 100%;
- height: 100%;
- opacity: 0.2;
- position: absolute;
- border-radius: var(--border-radius);
- background: none;
- transition: background 0.5s ease;
-}
-
-.tab svg {
- height: 30px;
- width: 30px;
- min-width: 30px;
- fill: var(--black);
- transition: fill 0.5s ease;
-}
-
-.tab.active::before {
- background: var(--active-color);
-}
-
-.tab span {
- font-weight: 700;
- margin-left: 10px;
- transition: color 0.5s ease;
-}
-
-.tab.active span {
- color: var(--active-color);
-}
-
-.tab.active svg {
- fill: var(--active-color);
-}
-
-.tab a {
- padding: 16px;
- display: flex;
- align-items: center;
- font-size: 20px;
- overflow: hidden;
- position: relative;
-}
-
-.cards {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
- margin-top: 40px;
-}
-
-.content-card {
- width: 48%;
- margin-bottom: 26px;
-}
-
-.content-card .info::after {
- content: "";
- display: block;
- width: 100%;
- height: 3px;
- bottom: -5px;
- background: var(--active-color);
- opacity: 0.5;
-}
-
-.content-card img {
- border-radius: 6px;
-}
-
-.content-card h3 {
- margin: 0 0 5px;
-}
-
-.content-card .info {
- padding: 10px 0;
-}
+* {
+ box-sizing: border-box;
+}
+
+:root {
+ --white: #fff;
+ --black: #333;
+ --active-color: #f1f1f1;
+ --border-radius: 40px;
+}
+
+body {
+ -webkit-font-smoothing: antialiased;
+ font-family: Arial, Helvetica, sans-serif;
+ background: var(--active-color);
+ transition: background 1.5s ease;
+}
+
+img {
+ max-width: 100%;
+ vertical-align: middle;
+}
+
+.tabs-component {
+ width: 100%;
+ height: 100%;
+ margin: auto;
+ padding: 40px;
+ border-radius: var(--border-radius);
+}
+
+.tab-links {
+ padding: 0;
+ margin: 0 auto 20px;
+ list-style: none;
+ max-width: 400px;
+ display: flex;
+ justify-content: space-between;
+}
+
+.tab {
+ position: relative;
+}
+
+.tab a {
+ text-decoration: none;
+ color: var(--black);
+}
+
+.tab::before {
+ content: "";
+ width: 100%;
+ height: 100%;
+ opacity: 0.2;
+ position: absolute;
+ border-radius: var(--border-radius);
+ background: none;
+ transition: background 0.5s ease;
+}
+
+.tab svg {
+ height: 30px;
+ width: 30px;
+ min-width: 30px;
+ fill: var(--black);
+ transition: fill 0.5s ease;
+}
+
+.tab.active::before {
+ background: var(--active-color);
+}
+
+.tab span {
+ font-weight: 700;
+ margin-left: 10px;
+ transition: color 0.5s ease;
+}
+
+.tab.active span {
+ color: var(--active-color);
+}
+
+.tab.active svg {
+ fill: var(--active-color);
+}
+
+.tab a {
+ padding: 16px;
+ display: flex;
+ align-items: center;
+ font-size: 20px;
+ overflow: hidden;
+ position: relative;
+}
+
+.cards {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ margin-top: 40px;
+}
+
+.content-card {
+ width: 48%;
+ margin-bottom: 26px;
+}
+
+.content-card .info::after {
+ content: "";
+ display: block;
+ width: 100%;
+ height: 3px;
+ bottom: -5px;
+ background: var(--active-color);
+ opacity: 0.5;
+}
+
+.content-card img {
+ border-radius: 6px;
+}
+
+.content-card h3 {
+ margin: 0 0 5px;
+}
+
+.content-card .info {
+ padding: 10px 0;
+}
diff --git a/src/pages/Settings/tabs.tsx b/src/pages/Settings/tabs.tsx
index 59f786c..617ab52 100644
--- a/src/pages/Settings/tabs.tsx
+++ b/src/pages/Settings/tabs.tsx
@@ -1,42 +1,42 @@
-import Proxy from "./Proxy";
-import TabSettings from "./TabSettings";
-import Misc from "./Misc";
-import Customization from "./Customization";
-
-import { GoBrowser } from "react-icons/go";
-import { AiOutlineLaptop } from "react-icons/ai";
-import { FaPalette } from "react-icons/fa";
-import { FaGear } from "react-icons/fa6";
-
-const tabs = [
- {
- title: "settings.tabs.proxy",
- id: "proxy",
- icon: ,
- color: "#5d5dff",
- content: Proxy
- },
- {
- title: "settings.tabs.tab",
- id: "tab",
- icon: ,
- color: "#67bb67",
- content: TabSettings
- },
- {
- title: "settings.tabs.custom",
- id: "custom",
- icon: ,
- color: "#63a7c7",
- content: Customization
- },
- {
- title: "settings.tabs.misc",
- id: "misc",
- icon: ,
- color: "#f56868",
- content: Misc
- }
-];
-
-export default tabs;
+import Proxy from "./Proxy";
+import TabSettings from "./TabSettings";
+import Misc from "./Misc";
+import Customization from "./Customization";
+
+import { GoBrowser } from "react-icons/go";
+import { AiOutlineLaptop } from "react-icons/ai";
+import { FaPalette } from "react-icons/fa";
+import { FaGear } from "react-icons/fa6";
+
+const tabs = [
+ {
+ title: "settings.tabs.proxy",
+ id: "proxy",
+ icon: ,
+ color: "#5d5dff",
+ content: Proxy
+ },
+ {
+ title: "settings.tabs.tab",
+ id: "tab",
+ icon: ,
+ color: "#67bb67",
+ content: TabSettings
+ },
+ {
+ title: "settings.tabs.custom",
+ id: "custom",
+ icon: ,
+ color: "#63a7c7",
+ content: Customization
+ },
+ {
+ title: "settings.tabs.misc",
+ id: "misc",
+ icon: ,
+ color: "#f56868",
+ content: Misc
+ }
+];
+
+export default tabs;
diff --git a/src/pages/_404.tsx b/src/pages/_404.tsx
index 1fd4e7c..2db4d9f 100644
--- a/src/pages/_404.tsx
+++ b/src/pages/_404.tsx
@@ -1,26 +1,26 @@
-import { useTranslation } from "react-i18next";
-import { Link } from "preact-router";
-import { HeaderRoute } from "../components/HeaderRoute";
-
-export function NotFound() {
- const { t } = useTranslation();
-
- return (
-
-
-
-

-
-
{t("404.text")}
-
404
-
-
-
-
-
-
-
- );
-}
+import { useTranslation } from "react-i18next";
+import { Link } from "preact-router";
+import { HeaderRoute } from "../components/HeaderRoute";
+
+export function NotFound() {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+

+
+
{t("404.text")}
+
404
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/discord.tsx b/src/pages/discord.tsx
index b0b8d24..87d5a2c 100644
--- a/src/pages/discord.tsx
+++ b/src/pages/discord.tsx
@@ -1,29 +1,32 @@
-import { useTranslation } from "react-i18next";
-import { HeaderRoute } from "../components/HeaderRoute";
-
-export function DiscordPage() {
- const { t } = useTranslation();
-
- return (
-
-
-
- );
-}
+import { useTranslation } from "react-i18next";
+import { HeaderRoute } from "../components/HeaderRoute";
+
+export function DiscordPage() {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ );
+}
diff --git a/src/style.css b/src/style.css
index 739b03e..e501c2e 100644
--- a/src/style.css
+++ b/src/style.css
@@ -1,5 +1,5 @@
-@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;700;900&display=swap");
-
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;700;900&display=swap");
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/src/themes/main.css b/src/themes/main.css
index 4225b6c..472676d 100644
--- a/src/themes/main.css
+++ b/src/themes/main.css
@@ -1,28 +1,28 @@
-@import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap");
-
-:root {
- --background-primary: #191724;
- --background-lighter: #16121f;
- --navbar-color: #26233a;
- --navbar-height: 60px;
- --navbar-text-color: #7967dd;
- --navbar-link-color: #e0def4;
- --navbar-link-hover-color: gray;
- --navbar-font: "Roboto";
- --input-text-color: #e0def4;
- --input-placeholder-color: white;
- --input-background-color: #1f1d2e;
- --input-border-color: #eb6f92;
- --input-border-size: 1.3px;
- --navbar-logo-filter: none;
- --dropdown-option-hover-color: #312a49;
-}
-
-.font-inter {
- font-family: "Inter", sans-serif;
- font-weight: 300;
-}
-
-.font-roboto {
- font-family: "Roboto";
-}
+@import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap");
+
+:root {
+ --background-primary: #191724;
+ --background-lighter: #16121f;
+ --navbar-color: #26233a;
+ --navbar-height: 60px;
+ --navbar-text-color: #7967dd;
+ --navbar-link-color: #e0def4;
+ --navbar-link-hover-color: gray;
+ --navbar-font: "Roboto";
+ --input-text-color: #e0def4;
+ --input-placeholder-color: white;
+ --input-background-color: #1f1d2e;
+ --input-border-color: #eb6f92;
+ --input-border-size: 1.3px;
+ --navbar-logo-filter: none;
+ --dropdown-option-hover-color: #312a49;
+}
+
+.font-inter {
+ font-family: "Inter", sans-serif;
+ font-weight: 300;
+}
+
+.font-roboto {
+ font-family: "Roboto";
+}
diff --git a/src/util/RammerheadEncode.ts b/src/util/RammerheadEncode.ts
index 3b8e333..b3808d3 100644
--- a/src/util/RammerheadEncode.ts
+++ b/src/util/RammerheadEncode.ts
@@ -1,176 +1,177 @@
-export function RammerheadEncode(baseUrl) { // Hellhead
- const mod = (n, m) => ((n % m) + m) % m;
- const baseDictionary =
- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~-";
- const shuffledIndicator = "_rhs";
- const generateDictionary = function () {
- let str = "";
- const split = baseDictionary.split("");
- while (split.length > 0) {
- str += split.splice(Math.floor(Math.random() * split.length), 1)[0];
- }
- return str;
- };
- interface StrShuffler {
- dictionary: any;
- }
- class StrShuffler {
- constructor(dictionary = generateDictionary()) {
- this.dictionary = dictionary;
- }
- shuffle(str) {
- if (str.startsWith(shuffledIndicator)) {
- return str;
- }
- let shuffledStr = "";
- for (let i = 0; i < str.length; i++) {
- const char = str.charAt(i);
- const idx = baseDictionary.indexOf(char);
- if (char === "%" && str.length - i >= 3) {
- shuffledStr += char;
- shuffledStr += str.charAt(++i);
- shuffledStr += str.charAt(++i);
- } else if (idx === -1) {
- shuffledStr += char;
- } else {
- shuffledStr += this.dictionary.charAt(
- mod(idx + i, baseDictionary.length)
- );
- }
- }
- return shuffledIndicator + shuffledStr;
- }
- unshuffle(str) {
- if (!str.startsWith(shuffledIndicator)) {
- return str;
- }
-
- str = str.slice(shuffledIndicator.length);
-
- let unshuffledStr = "";
- for (let i = 0; i < str.length; i++) {
- const char = str.charAt(i);
- const idx = this.dictionary.indexOf(char);
- if (char === "%" && str.length - i >= 3) {
- unshuffledStr += char;
- unshuffledStr += str.charAt(++i);
- unshuffledStr += str.charAt(++i);
- } else if (idx === -1) {
- unshuffledStr += char;
- } else {
- unshuffledStr += baseDictionary.charAt(
- mod(idx - i, baseDictionary.length)
- );
- }
- }
- return unshuffledStr;
- }
- }
- function get(url, callback, shush = false) {
- var request = new XMLHttpRequest();
- request.open("GET", url, true);
- request.send();
-
- request.onerror = function () {
- if (!shush) console.log("Cannot communicate with the server");
- };
- request.onload = function () {
- if (request.status === 200) {
- callback(request.responseText);
- } else {
- if (!shush)
- console.log(
- 'unexpected server response to not match "200". Server says "' +
- request.responseText +
- '"'
- );
- }
- };
- }
- var api = {
- newsession(callback) {
- get("/newsession", callback);
- },
- sessionexists(id, callback) {
- get("/sessionexists?id=" + encodeURIComponent(id), function (res) {
- if (res === "exists") return callback(true);
- if (res === "not found") return callback(false);
- console.log("unexpected response from server. received" + res);
- });
- },
- shuffleDict(id, callback) {
- console.log("Shuffling", id);
- get("/api/shuffleDict?id=" + encodeURIComponent(id), function (res) {
- callback(JSON.parse(res));
- });
- }
- };
- var localStorageKey = "rammerhead_sessionids";
- var localStorageKeyDefault = "rammerhead_default_sessionid";
- var sessionIdsStore = {
- get() {
- var rawData = localStorage.getItem(localStorageKey);
- if (!rawData) return [];
- try {
- var data = JSON.parse(rawData);
- if (!Array.isArray(data)) throw "getout";
- return data;
- } catch (e) {
- return [];
- }
- },
- set(data) {
- if (!data || !Array.isArray(data)) throw new TypeError("must be array");
- localStorage.setItem(localStorageKey, JSON.stringify(data));
- },
- getDefault() {
- var sessionId = localStorage.getItem(localStorageKeyDefault);
- if (sessionId) {
- var data = sessionIdsStore.get();
- data.filter(function (e) {
- return e.id === sessionId;
- });
- if (data.length) return data[0];
- }
- return null;
- },
- setDefault(id) {
- localStorage.setItem(localStorageKeyDefault, id);
- }
- };
- function addSession(id) {
- var data = sessionIdsStore.get();
- data.unshift({ id: id, createdOn: new Date().toLocaleString() });
- sessionIdsStore.set(data);
- }
- function getSessionId() {
- return new Promise((resolve) => {
- var id = localStorage.getItem("session-string");
- api.sessionexists(id, function (value) {
- if (!value) {
- console.log("Session validation failed");
- api.newsession(function (id) {
- addSession(id);
- localStorage.setItem("session-string", id);
- console.log(id);
- console.log("^ new id");
- resolve(id);
- });
- } else {
- resolve(id);
- }
- });
- });
- }
- var ProxyHref;
-
- return getSessionId().then((id) => {
- return new Promise((resolve, reject) => {
- api.shuffleDict(id, function (shuffleDict) {
- var shuffler = new StrShuffler(shuffleDict);
- ProxyHref = "/" + id + "/" + shuffler.shuffle(baseUrl);
- resolve(ProxyHref);
- });
- });
- });
-}
+export function RammerheadEncode(baseUrl) {
+ // Hellhead
+ const mod = (n, m) => ((n % m) + m) % m;
+ const baseDictionary =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~-";
+ const shuffledIndicator = "_rhs";
+ const generateDictionary = function () {
+ let str = "";
+ const split = baseDictionary.split("");
+ while (split.length > 0) {
+ str += split.splice(Math.floor(Math.random() * split.length), 1)[0];
+ }
+ return str;
+ };
+ interface StrShuffler {
+ dictionary: any;
+ }
+ class StrShuffler {
+ constructor(dictionary = generateDictionary()) {
+ this.dictionary = dictionary;
+ }
+ shuffle(str) {
+ if (str.startsWith(shuffledIndicator)) {
+ return str;
+ }
+ let shuffledStr = "";
+ for (let i = 0; i < str.length; i++) {
+ const char = str.charAt(i);
+ const idx = baseDictionary.indexOf(char);
+ if (char === "%" && str.length - i >= 3) {
+ shuffledStr += char;
+ shuffledStr += str.charAt(++i);
+ shuffledStr += str.charAt(++i);
+ } else if (idx === -1) {
+ shuffledStr += char;
+ } else {
+ shuffledStr += this.dictionary.charAt(
+ mod(idx + i, baseDictionary.length)
+ );
+ }
+ }
+ return shuffledIndicator + shuffledStr;
+ }
+ unshuffle(str) {
+ if (!str.startsWith(shuffledIndicator)) {
+ return str;
+ }
+
+ str = str.slice(shuffledIndicator.length);
+
+ let unshuffledStr = "";
+ for (let i = 0; i < str.length; i++) {
+ const char = str.charAt(i);
+ const idx = this.dictionary.indexOf(char);
+ if (char === "%" && str.length - i >= 3) {
+ unshuffledStr += char;
+ unshuffledStr += str.charAt(++i);
+ unshuffledStr += str.charAt(++i);
+ } else if (idx === -1) {
+ unshuffledStr += char;
+ } else {
+ unshuffledStr += baseDictionary.charAt(
+ mod(idx - i, baseDictionary.length)
+ );
+ }
+ }
+ return unshuffledStr;
+ }
+ }
+ function get(url, callback, shush = false) {
+ var request = new XMLHttpRequest();
+ request.open("GET", url, true);
+ request.send();
+
+ request.onerror = function () {
+ if (!shush) console.log("Cannot communicate with the server");
+ };
+ request.onload = function () {
+ if (request.status === 200) {
+ callback(request.responseText);
+ } else {
+ if (!shush)
+ console.log(
+ 'unexpected server response to not match "200". Server says "' +
+ request.responseText +
+ '"'
+ );
+ }
+ };
+ }
+ var api = {
+ newsession(callback) {
+ get("/newsession", callback);
+ },
+ sessionexists(id, callback) {
+ get("/sessionexists?id=" + encodeURIComponent(id), function (res) {
+ if (res === "exists") return callback(true);
+ if (res === "not found") return callback(false);
+ console.log("unexpected response from server. received" + res);
+ });
+ },
+ shuffleDict(id, callback) {
+ console.log("Shuffling", id);
+ get("/api/shuffleDict?id=" + encodeURIComponent(id), function (res) {
+ callback(JSON.parse(res));
+ });
+ }
+ };
+ var localStorageKey = "rammerhead_sessionids";
+ var localStorageKeyDefault = "rammerhead_default_sessionid";
+ var sessionIdsStore = {
+ get() {
+ var rawData = localStorage.getItem(localStorageKey);
+ if (!rawData) return [];
+ try {
+ var data = JSON.parse(rawData);
+ if (!Array.isArray(data)) throw "getout";
+ return data;
+ } catch (e) {
+ return [];
+ }
+ },
+ set(data) {
+ if (!data || !Array.isArray(data)) throw new TypeError("must be array");
+ localStorage.setItem(localStorageKey, JSON.stringify(data));
+ },
+ getDefault() {
+ var sessionId = localStorage.getItem(localStorageKeyDefault);
+ if (sessionId) {
+ var data = sessionIdsStore.get();
+ data.filter(function (e) {
+ return e.id === sessionId;
+ });
+ if (data.length) return data[0];
+ }
+ return null;
+ },
+ setDefault(id) {
+ localStorage.setItem(localStorageKeyDefault, id);
+ }
+ };
+ function addSession(id) {
+ var data = sessionIdsStore.get();
+ data.unshift({ id: id, createdOn: new Date().toLocaleString() });
+ sessionIdsStore.set(data);
+ }
+ function getSessionId() {
+ return new Promise((resolve) => {
+ var id = localStorage.getItem("session-string");
+ api.sessionexists(id, function (value) {
+ if (!value) {
+ console.log("Session validation failed");
+ api.newsession(function (id) {
+ addSession(id);
+ localStorage.setItem("session-string", id);
+ console.log(id);
+ console.log("^ new id");
+ resolve(id);
+ });
+ } else {
+ resolve(id);
+ }
+ });
+ });
+ }
+ var ProxyHref;
+
+ return getSessionId().then((id) => {
+ return new Promise((resolve, reject) => {
+ api.shuffleDict(id, function (shuffleDict) {
+ var shuffler = new StrShuffler(shuffleDict);
+ ProxyHref = "/" + id + "/" + shuffler.shuffle(baseUrl);
+ resolve(ProxyHref);
+ });
+ });
+ });
+}
diff --git a/src/util/searchUtil.ts b/src/util/searchUtil.ts
index 177af52..4d56a26 100644
--- a/src/util/searchUtil.ts
+++ b/src/util/searchUtil.ts
@@ -1,10 +1,10 @@
-export function searchUtil(input: string, template: string) {
- try {
- return new URL(input).toString();
- } catch (error) {}
- try {
- const url = new URL(`http://${input}`);
- if (url.hostname.includes(".")) return url.toString();
- } catch (error) {}
- return template.replace("%s", encodeURIComponent(input));
-}
+export function searchUtil(input: string, template: string) {
+ try {
+ return new URL(input).toString();
+ } catch (error) {}
+ try {
+ const url = new URL(`http://${input}`);
+ if (url.hostname.includes(".")) return url.toString();
+ } catch (error) {}
+ return template.replace("%s", encodeURIComponent(input));
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index 7e5ee2b..c2e7717 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,21 +1,20 @@
-/** @type {import('tailwindcss').Config} */
-export default {
- content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
- theme: {
- colors: {
- primary: "var(--background-primary)",
- lighter: "var(--background-lighter)",
- "navbar-text-color": "var(--navbar-text-color)",
- "navbar-color": "var(--navbar-color)",
- "text-color": "var(--navbar-link-color)",
- "text-hover-color": "var(--navbar-link-hover-color)",
- input: "var(--input-background-color)",
- "input-text": "var(--input-text-color)",
- "input-border-color": "var(--input-border-color)",
- "dropdown-option-hover-color": "var(--dropdown-option-hover-color)",
- },
- extend: {}
- },
- plugins: []
-};
-
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
+ theme: {
+ colors: {
+ primary: "var(--background-primary)",
+ lighter: "var(--background-lighter)",
+ "navbar-text-color": "var(--navbar-text-color)",
+ "navbar-color": "var(--navbar-color)",
+ "text-color": "var(--navbar-link-color)",
+ "text-hover-color": "var(--navbar-link-hover-color)",
+ input: "var(--input-background-color)",
+ "input-text": "var(--input-text-color)",
+ "input-border-color": "var(--input-border-color)",
+ "dropdown-option-hover-color": "var(--dropdown-option-hover-color)"
+ },
+ extend: {}
+ },
+ plugins: []
+};
diff --git a/tsconfig.json b/tsconfig.json
index 7139d8b..fc7dd47 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,12 +1,12 @@
-{
- "compilerOptions": {
- "target": "ES2020",
- "module": "ESNext",
- "moduleResolution": "bundler",
- "noEmit": true,
- "jsx": "react-jsx",
- "jsxImportSource": "preact",
- "skipLibCheck": true,
- "paths": {}
- }
-}
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "jsxImportSource": "preact",
+ "skipLibCheck": true,
+ "paths": {}
+ }
+}
diff --git a/vite.config.ts b/vite.config.ts
index e04660d..0cbb19f 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,31 +1,31 @@
-import million from "million/compiler";
-import { defineConfig } from "vite";
-import preact from "@preact/preset-vite";
-import { viteStaticCopy } from "vite-plugin-static-copy";
-import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
-
-export default defineConfig({
- plugins: [
- viteStaticCopy({
- targets: [
- {
- // .replace fixes weird paths on Windows
- src: `${uvPath}/uv.*.js`.replace(/\\/g, "/"),
- dest: "uv",
- overwrite: false
- }
- ]
- }),
- million.vite({ auto: true }),
- preact()
- ],
- server: {
- proxy: {
- "/bare": {
- target: "http://localhost:8080/",
- changeOrigin: true,
- rewrite: (path) => path.replace(/^\/bare/, "")
- }
- }
- }
-});
+import million from "million/compiler";
+import { defineConfig } from "vite";
+import preact from "@preact/preset-vite";
+import { viteStaticCopy } from "vite-plugin-static-copy";
+import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
+
+export default defineConfig({
+ plugins: [
+ viteStaticCopy({
+ targets: [
+ {
+ // .replace fixes weird paths on Windows
+ src: `${uvPath}/uv.*.js`.replace(/\\/g, "/"),
+ dest: "uv",
+ overwrite: false
+ }
+ ]
+ }),
+ million.vite({ auto: true }),
+ preact()
+ ],
+ server: {
+ proxy: {
+ "/bare": {
+ target: "http://localhost:8080/",
+ changeOrigin: true,
+ rewrite: (path) => path.replace(/^\/bare/, "")
+ }
+ }
+ }
+});