Merge pull request #209 from NebulaServices/main

q
This commit is contained in:
rift 2024-01-12 12:22:15 -06:00 committed by GitHub
commit b38a597b7e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 2493 additions and 1378 deletions

View file

@ -2,12 +2,10 @@
NebulaWeb is an official flagship of Nebula Services and Nebula Developer Labs. NebulaWeb is a stunning, sleek, and functional web-proxy with support for thousands of popular sites. With NebulaWeb, the sky is the limit.
![license](https://img.shields.io/badge/License-GNU%20AGPL%20v3-blue)
## Features
- Stunning and highly functional UI
- 3 different backend proxies
- Hides your IP from sites
@ -18,20 +16,21 @@ NebulaWeb is an official flagship of Nebula Services and Nebula Developer Labs.
# Deployment
Table of contents
- Deployment
---
## Deployment
Run these commands on your server:
`git clone https://https://github.com/NebulaServices/Nebula.git`
`git clone https://github.com/NebulaServices/Nebula.git`
`pnpm i`
`npm run bstart`
You may also need to run `npm i -g pnpm tsx`
Thanks for using Nebula!
## Tech Stack
- TypeScript, Tailwind
@ -58,6 +57,7 @@ For support, join our discord: discord.gg/unblocker
- [Dynamic (one of the proxies we use)](https://github.com/NebulaServices/Dynamic)
- [Rammerhead (one of the proxies we use)](https://github.com/binary-person/rammerhead)
- [Bare Server Node](https://github.com/tomphttp/bare-server-node)
- [Catppuccin (for the themes)](https://github.com/catppuccin/catppuccin)
## License

View file

@ -14,6 +14,7 @@
<script src="/uv/uv.bundle.js"></script>
<script src="/uv/uv.config.js"></script>
<script src="/dynamic/dynamic.config.js"></script>
<script src="/localforage/localforage.min.js" defer></script>
<script>
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {

View file

@ -13,13 +13,16 @@
"dependencies": {
"@fastify/compress": "^6.5.0",
"@fastify/static": "^6.12.0",
"@titaniumnetwork-dev/ultraviolet": "^2.0.0",
"@nebula-services/dynamic": "0.7.2-patch.2",
"@nebula-services/ultraviolet": "1.0.1-1.patch.5",
"@tomphttp/bare-server-node": "^2.0.1",
"classnames": "^2.3.2",
"crypto-js": "^4.2.0",
"fastify": "^4.25.1",
"framer-motion": "^10.16.16",
"i18next": "^23.7.9",
"i18next-browser-languagedetector": "^7.2.0",
"localforage": "^1.10.0",
"million": "^2.6.4",
"preact": "^10.13.1",
"preact-iso": "^2.3.2",
@ -29,6 +32,7 @@
"react-helmet": "^6.1.0",
"react-i18next": "^13.5.0",
"react-icons": "^4.12.0",
"react-toastify": "^9.1.3",
"tsx": "^4.7.0"
},
"devDependencies": {

516
pnpm-lock.yaml generated
View file

@ -11,27 +11,36 @@ dependencies:
'@fastify/static':
specifier: ^6.12.0
version: 6.12.0
'@titaniumnetwork-dev/ultraviolet':
specifier: ^2.0.0
version: 2.0.0
'@nebula-services/dynamic':
specifier: 0.7.2-patch.2
version: 0.7.2-patch.2
'@nebula-services/ultraviolet':
specifier: 1.0.1-1.patch.5
version: 1.0.1-1.patch.5
'@tomphttp/bare-server-node':
specifier: ^2.0.1
version: 2.0.1
classnames:
specifier: ^2.3.2
version: 2.3.2
crypto-js:
specifier: ^4.2.0
version: 4.2.0
fastify:
specifier: ^4.25.1
version: 4.25.1
framer-motion:
specifier: ^10.16.16
version: 10.16.16(react@18.2.0)
version: 10.16.16(react-dom@18.2.0)(react@18.2.0)
i18next:
specifier: ^23.7.9
version: 23.7.10
i18next-browser-languagedetector:
specifier: ^7.2.0
version: 7.2.0
localforage:
specifier: ^1.10.0
version: 1.10.0
million:
specifier: ^2.6.4
version: 2.6.4
@ -55,10 +64,13 @@ dependencies:
version: 6.1.0(react@18.2.0)
react-i18next:
specifier: ^13.5.0
version: 13.5.0(i18next@23.7.10)(react@18.2.0)
version: 13.5.0(i18next@23.7.10)(react-dom@18.2.0)(react@18.2.0)
react-icons:
specifier: ^4.12.0
version: 4.12.0(react@18.2.0)
react-toastify:
specifier: ^9.1.3
version: 9.1.3(react-dom@18.2.0)(react@18.2.0)
tsx:
specifier: ^4.7.0
version: 4.7.0
@ -383,6 +395,14 @@ packages:
'@babel/helper-validator-identifier': 7.22.20
to-fast-properties: 2.0.0
/@dynamic-pkg/mime@1.0.1:
resolution: {integrity: sha512-uZ16uKblCpCWRvF2oPx+hE3Oo+co6NLoEFdA4vWka7+ywoWcQlpbXkNucWoSvLS8V0eTqZIEGx3xJ7rwPUXleg==}
dev: false
/@dynamic-pkg/mutation@1.0.0:
resolution: {integrity: sha512-Xi61JMWcP022hBsYyKJ+0iOzHzSkFf+5qbCs0I2tFmwNaH6jB1kkHGPOEtXmn6/wNgE7/AJV0rj5DEGSnamlnw==}
dev: false
/@emotion/is-prop-valid@0.8.8:
resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==}
requiresBuild: true
@ -978,6 +998,50 @@ packages:
resolution: {integrity: sha512-n3/+wko8WFd/fbiPCOuBB6HfKL6hTcygFEZ/MpmvpMRbgDSdlNMopDFGjsoTYqCbzTVTX9TL/StXco4yx2v58Q==}
dev: true
/@nebula-services/dynamic@0.7.2-patch.2:
resolution: {integrity: sha512-0g1ygwVNS0dmT38NIeZYc2Z5HiZKHT3tP7ZagIeWC/VlcZjINIPR4ThNndWVaGiZey2Y2JS2807ABb41OSYTrw==}
dependencies:
'@dynamic-pkg/mime': 1.0.1
'@dynamic-pkg/mutation': 1.0.0
'@fastify/compress': 6.5.0
'@fastify/static': 6.12.0
'@tomphttp/bare-client': 2.2.0-alpha
'@tomphttp/bare-server-node': 2.0.1
acorn: 8.11.2
astring: 1.8.6
chalk: 5.3.0
cookie: 0.5.0
crypto-js: 4.2.0
domhandler: 5.0.3
esbuild: 0.19.10
fastify: 4.25.1
git-commit-info: 2.0.2
idb: 7.1.1
open: 9.1.0
parse5: 7.1.2
path-browserify: 1.0.1
set-cookie-parser: 2.6.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
dev: false
/@nebula-services/ultraviolet@1.0.1-1.patch.5:
resolution: {integrity: sha512-EDwbh+AXPg+JxPcPhRHJh6crLh1AHSodcAgfO47ug4paoLkWXE0ELU5Tm0Um38kguTBHzTOPFSzNULpaFbhFLw==}
dependencies:
'@tomphttp/bare-client': 1.1.2-beta.3
crypto-js: 4.2.0
css-tree: 2.3.1
esotope-hammerhead: 0.6.7
events: 3.3.0
idb: 7.1.1
meriyah: 4.3.9
mime-db: 1.52.0
parse5: 7.1.2
set-cookie-parser: 2.6.0
dev: false
/@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1:
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
dependencies:
@ -1191,22 +1255,12 @@ packages:
dev: true
optional: true
/@titaniumnetwork-dev/ultraviolet@2.0.0:
resolution: {integrity: sha512-zRjwip5yFr1p3/1WTb7nmbqmJKNIoxvhbaKFaKr1eSw1Px/Y/nBwPZ+AW+aKVAPFZvx/wAb14eTf2BAH7zklaQ==}
dependencies:
'@tomphttp/bare-client': 2.1.0
css-tree: 2.3.1
esotope-hammerhead: 0.6.7
events: 3.3.0
idb: 7.1.1
meriyah: 4.3.9
mime-db: 1.52.0
parse5: 7.1.2
set-cookie-parser: 2.6.0
/@tomphttp/bare-client@1.1.2-beta.3:
resolution: {integrity: sha512-WyIVnSAqzfrLejmOhh/l/LtDOeK+SHnBGi/z+QyliVP1T1JxoNE5eecwxlV+osM9J6FTAYVGNHr8/5bubaIj6Q==}
dev: false
/@tomphttp/bare-client@2.1.0:
resolution: {integrity: sha512-0s2g3bpKAxwk7sOsfewpngLF+2lQrS0mxnga+6qIzKCoYdOKd5+Lm3lkEDHO0cWIEqMbgRZB2wjW1+NQ2XbGWA==}
/@tomphttp/bare-client@2.2.0-alpha:
resolution: {integrity: sha512-xhcflOpwr92tkpp8SoDhB3nK3LHMBIjx+vgow37XobQew2k0/mXSxmaU7BsDFpOIa1CcLCEsR8gWn0v7Cy9+7Q==}
dev: false
/@tomphttp/bare-server-node@2.0.1:
@ -1596,6 +1650,11 @@ packages:
'@mdn/browser-compat-data': 5.4.5
dev: true
/astring@1.8.6:
resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==}
hasBin: true
dev: false
/async-exit-hook@2.0.1:
resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==}
engines: {node: '>=0.12.0'}
@ -1664,6 +1723,11 @@ packages:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
/big-integer@1.6.52:
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
engines: {node: '>=0.6'}
dev: false
/binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@ -1676,6 +1740,13 @@ packages:
resolution: {integrity: sha512-Fk23J0+vRnI2eKDEDoUZXWtbMjijr098lKhuj4DKAfMKMCRVfJOuxXlbpxy0sTgbZ/Nr2N8MexmOir+GGI/ZMA==}
dev: false
/bplist-parser@0.2.0:
resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==}
engines: {node: '>= 5.10.0'}
dependencies:
big-integer: 1.6.52
dev: false
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
@ -1715,6 +1786,13 @@ packages:
ieee754: 1.2.1
dev: false
/bundle-name@3.0.0:
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
engines: {node: '>=12'}
dependencies:
run-applescript: 5.0.0
dev: false
/cacache@15.3.0:
resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==}
engines: {node: '>= 10'}
@ -1784,6 +1862,11 @@ packages:
supports-color: 7.2.0
dev: true
/chalk@5.3.0:
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
dev: false
/chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
@ -1827,6 +1910,11 @@ packages:
wrap-ansi: 7.0.0
dev: true
/clsx@1.2.1:
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
engines: {node: '>=6'}
dev: false
/color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
@ -1907,6 +1995,14 @@ packages:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: false
/cross-spawn@5.1.0:
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
dependencies:
lru-cache: 4.1.5
shebang-command: 1.2.0
which: 1.3.1
dev: false
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@ -1914,7 +2010,10 @@ packages:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
dev: true
/crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
dev: false
/crypto-md5@1.0.0:
resolution: {integrity: sha512-65Mtei8+EkSIK+5Ie4gpWXoJ/5bgpqPXFknHHXAyhDqKsEAAzUslGd8mOeawbfcuQ8fADNKcF4xQA3fqlZJ8Ig==}
@ -1987,6 +2086,24 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
/default-browser-id@3.0.0:
resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==}
engines: {node: '>=12'}
dependencies:
bplist-parser: 0.2.0
untildify: 4.0.0
dev: false
/default-browser@4.0.0:
resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==}
engines: {node: '>=14.16'}
dependencies:
bundle-name: 3.0.0
default-browser-id: 3.0.0
execa: 7.2.0
titleize: 3.0.0
dev: false
/define-data-property@1.1.1:
resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
engines: {node: '>= 0.4'}
@ -1996,6 +2113,11 @@ packages:
has-property-descriptors: 1.0.1
dev: true
/define-lazy-prop@3.0.0:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'}
dev: false
/define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
@ -2048,6 +2170,17 @@ packages:
esutils: 2.0.3
dev: true
/domelementtype@2.3.0:
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
dev: false
/domhandler@5.0.3:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
dependencies:
domelementtype: 2.3.0
dev: false
/dotenv@16.3.1:
resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
engines: {node: '>=12'}
@ -2504,6 +2637,64 @@ packages:
engines: {node: '>=0.8.x'}
dev: false
/execa@0.6.3:
resolution: {integrity: sha512-/teX3MDLFBdYUhRk8WCBYboIMUmqeizu0m9Z3YF3JWrbEh/SlZg00vLJSaAGWw3wrZ9tE0buNw79eaAPYhUuvg==}
engines: {node: '>=4'}
dependencies:
cross-spawn: 5.1.0
get-stream: 3.0.0
is-stream: 1.1.0
npm-run-path: 2.0.2
p-finally: 1.0.0
signal-exit: 3.0.7
strip-eof: 1.0.0
dev: false
/execa@4.1.0:
resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
engines: {node: '>=10'}
dependencies:
cross-spawn: 7.0.3
get-stream: 5.2.0
human-signals: 1.1.1
is-stream: 2.0.1
merge-stream: 2.0.0
npm-run-path: 4.0.1
onetime: 5.1.2
signal-exit: 3.0.7
strip-final-newline: 2.0.0
dev: false
/execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
dependencies:
cross-spawn: 7.0.3
get-stream: 6.0.1
human-signals: 2.1.0
is-stream: 2.0.1
merge-stream: 2.0.0
npm-run-path: 4.0.1
onetime: 5.1.2
signal-exit: 3.0.7
strip-final-newline: 2.0.0
dev: false
/execa@7.2.0:
resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
dependencies:
cross-spawn: 7.0.3
get-stream: 6.0.1
human-signals: 4.3.1
is-stream: 3.0.0
merge-stream: 2.0.0
npm-run-path: 5.2.0
onetime: 6.0.0
signal-exit: 3.0.7
strip-final-newline: 3.0.0
dev: false
/fast-content-type-parse@1.1.0:
resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==}
dev: false
@ -2651,7 +2842,7 @@ packages:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
dev: true
/framer-motion@10.16.16(react@18.2.0):
/framer-motion@10.16.16(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-je6j91rd7NmUX7L1XHouwJ4v3R+SO4umso2LUcgOct3rHZ0PajZ80ETYZTajzEXEl9DlKyzjyt4AvGQ+lrebOw==}
peerDependencies:
react: ^18.0.0
@ -2663,6 +2854,7 @@ packages:
optional: true
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
tslib: 2.6.2
optionalDependencies:
'@emotion/is-prop-valid': 0.8.8
@ -2768,6 +2960,23 @@ packages:
hasown: 2.0.0
dev: true
/get-stream@3.0.0:
resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==}
engines: {node: '>=4'}
dev: false
/get-stream@5.2.0:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'}
dependencies:
pump: 3.0.0
dev: false
/get-stream@6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
dev: false
/get-symbol-description@1.0.0:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
engines: {node: '>= 0.4'}
@ -2782,6 +2991,14 @@ packages:
resolve-pkg-maps: 1.0.0
dev: false
/git-commit-info@2.0.2:
resolution: {integrity: sha512-QOgPqeTkFiIQr3TW/ekG2U6s1x7OkNdR+2XsapmXHiGImO5Qx2cilx2HmGPrihIqmV0WWCo5H+B938lQ/vAAfA==}
dependencies:
execa: 4.1.0
is-git-repository: 1.1.1
path-is-absolute: 1.0.1
dev: false
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -2965,6 +3182,21 @@ packages:
- supports-color
dev: false
/human-signals@1.1.1:
resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
engines: {node: '>=8.12.0'}
dev: false
/human-signals@2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
dev: false
/human-signals@4.3.1:
resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
engines: {node: '>=14.18.0'}
dev: false
/humanize-ms@1.2.1:
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
requiresBuild: true
@ -3014,6 +3246,10 @@ packages:
engines: {node: '>= 4'}
dev: true
/immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
dev: false
/import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
@ -3134,6 +3370,18 @@ packages:
has-tostringtag: 1.0.0
dev: true
/is-docker@2.2.1:
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
engines: {node: '>=8'}
hasBin: true
dev: false
/is-docker@3.0.0:
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
hasBin: true
dev: false
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@ -3155,12 +3403,27 @@ packages:
has-tostringtag: 1.0.0
dev: true
/is-git-repository@1.1.1:
resolution: {integrity: sha512-hxLpJytJnIZ5Og5QsxSkzmb8Qx8rGau9bio1JN/QtXcGEFuSsQYau0IiqlsCwftsfVYjF1mOq6uLdmwNSspgpA==}
dependencies:
execa: 0.6.3
path-is-absolute: 1.0.1
dev: false
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
/is-inside-container@1.0.0:
resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
engines: {node: '>=14.16'}
hasBin: true
dependencies:
is-docker: 3.0.0
dev: false
/is-lambda@1.0.1:
resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
requiresBuild: true
@ -3210,6 +3473,21 @@ packages:
call-bind: 1.0.5
dev: true
/is-stream@1.1.0:
resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
engines: {node: '>=0.10.0'}
dev: false
/is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
dev: false
/is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: false
/is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
@ -3248,6 +3526,13 @@ packages:
get-intrinsic: 1.2.2
dev: true
/is-wsl@2.2.0:
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
engines: {node: '>=8'}
dependencies:
is-docker: 2.2.1
dev: false
/isarray@1.0.0:
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
dev: false
@ -3357,6 +3642,12 @@ packages:
type-check: 0.4.0
dev: true
/lie@3.1.1:
resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==}
dependencies:
immediate: 3.0.6
dev: false
/light-my-request@5.11.0:
resolution: {integrity: sha512-qkFCeloXCOMpmEdZ/MV91P8AT4fjwFXWaAFz3lUeStM8RcoM1ks4J/F8r1b3r6y/H4u3ACEJ1T+Gv5bopj7oDA==}
dependencies:
@ -3379,6 +3670,12 @@ packages:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
/localforage@1.10.0:
resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==}
dependencies:
lie: 3.1.1
dev: false
/locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
@ -3407,6 +3704,13 @@ packages:
resolution: {integrity: sha512-qkisDmHMe8gxKujmC1BdaqgkoFlioLDCUwaFBA3lX8Ilhr3YzsasbGYaiADMjxQnj+aiZUKgGKe/BN3skMwXWw==}
dev: false
/lru-cache@4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
dependencies:
pseudomap: 1.0.2
yallist: 2.1.2
dev: false
/lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
dependencies:
@ -3468,6 +3772,10 @@ packages:
readable-stream: 2.3.8
dev: false
/merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
dev: false
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@ -3524,6 +3832,16 @@ packages:
hasBin: true
dev: false
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
dev: false
/mimic-fn@4.0.0:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
engines: {node: '>=12'}
dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
@ -3718,6 +4036,27 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/npm-run-path@2.0.2:
resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
engines: {node: '>=4'}
dependencies:
path-key: 2.0.1
dev: false
/npm-run-path@4.0.1:
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
engines: {node: '>=8'}
dependencies:
path-key: 3.1.1
dev: false
/npm-run-path@5.2.0:
resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
path-key: 4.0.0
dev: false
/npmlog@5.0.1:
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
dependencies:
@ -3811,6 +4150,30 @@ packages:
dependencies:
wrappy: 1.0.2
/onetime@5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'}
dependencies:
mimic-fn: 2.1.0
dev: false
/onetime@6.0.0:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
engines: {node: '>=12'}
dependencies:
mimic-fn: 4.0.0
dev: false
/open@9.1.0:
resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==}
engines: {node: '>=14.16'}
dependencies:
default-browser: 4.0.0
define-lazy-prop: 3.0.0
is-inside-container: 1.0.0
is-wsl: 2.2.0
dev: false
/optionator@0.9.3:
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
engines: {node: '>= 0.8.0'}
@ -3827,6 +4190,11 @@ packages:
resolution: {integrity: sha512-E3Orl5pvDJXnVmpaAA2TeNNpNhTMl4o5HghuWhOivBjEiTnJSrMYSa5uZMek1lBEvu8kKEsa2YgVcGFVDqX/9w==}
dev: false
/p-finally@1.0.0:
resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
engines: {node: '>=4'}
dev: false
/p-is-promise@3.0.0:
resolution: {integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==}
engines: {node: '>=8'}
@ -3871,6 +4239,10 @@ packages:
entities: 4.5.0
dev: false
/path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
dev: false
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@ -3880,10 +4252,19 @@ packages:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
/path-key@2.0.1:
resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
engines: {node: '>=4'}
dev: false
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
dev: true
/path-key@4.0.0:
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
engines: {node: '>=12'}
dev: false
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@ -4175,6 +4556,10 @@ packages:
ipaddr.js: 1.9.1
dev: false
/pseudomap@1.0.2:
resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
dev: false
/psl@1.9.0:
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
dev: false
@ -4206,6 +4591,16 @@ packages:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
dev: false
/react-dom@18.2.0(react@18.2.0):
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
peerDependencies:
react: ^18.2.0
dependencies:
loose-envify: 1.4.0
react: 18.2.0
scheduler: 0.23.0
dev: false
/react-fast-compare@3.2.2:
resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==}
dev: false
@ -4222,7 +4617,7 @@ packages:
react-side-effect: 2.1.2(react@18.2.0)
dev: false
/react-i18next@13.5.0(i18next@23.7.10)(react@18.2.0):
/react-i18next@13.5.0(i18next@23.7.10)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA==}
peerDependencies:
i18next: '>= 23.2.3'
@ -4239,6 +4634,7 @@ packages:
html-parse-stringify: 3.0.1
i18next: 23.7.10
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/react-icons@4.12.0(react@18.2.0):
@ -4260,6 +4656,17 @@ packages:
react: 18.2.0
dev: false
/react-toastify@9.1.3(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==}
peerDependencies:
react: '>=16'
react-dom: '>=16'
dependencies:
clsx: 1.2.1
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@ -4450,6 +4857,13 @@ packages:
fsevents: 2.3.3
dev: true
/run-applescript@5.0.0:
resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==}
engines: {node: '>=12'}
dependencies:
execa: 5.1.1
dev: false
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
@ -4503,6 +4917,12 @@ packages:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: false
/scheduler@0.23.0:
resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
dependencies:
loose-envify: 1.4.0
dev: false
/secure-json-parse@2.7.0:
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
dev: false
@ -4554,17 +4974,27 @@ packages:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
dev: false
/shebang-command@1.2.0:
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
engines: {node: '>=0.10.0'}
dependencies:
shebang-regex: 1.0.0
dev: false
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
dependencies:
shebang-regex: 3.0.0
dev: true
/shebang-regex@1.0.0:
resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
engines: {node: '>=0.10.0'}
dev: false
/shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
dev: true
/shell-quote@1.8.1:
resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
@ -4776,6 +5206,21 @@ packages:
dependencies:
ansi-regex: 5.0.1
/strip-eof@1.0.0:
resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
engines: {node: '>=0.10.0'}
dev: false
/strip-final-newline@2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
dev: false
/strip-final-newline@3.0.0:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
dev: false
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@ -4925,6 +5370,11 @@ packages:
xtend: 4.0.2
dev: false
/titleize@3.0.0:
resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
engines: {node: '>=12'}
dev: false
/tmp-promise@1.1.0:
resolution: {integrity: sha512-8+Ah9aB1IRXCnIOxXZ0uFozV1nMU5xiu7hhFVUSxZ3bYu+psD4TzagCzVbexUCgNNGJnsmNDQlS4nG3mTyoNkw==}
dependencies:
@ -5127,6 +5577,11 @@ packages:
webpack-virtual-modules: 0.6.1
dev: false
/untildify@4.0.0:
resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
engines: {node: '>=8'}
dev: false
/update-browserslist-db@1.0.13(browserslist@4.22.2):
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
hasBin: true
@ -5281,6 +5736,13 @@ packages:
has-tostringtag: 1.0.0
dev: true
/which@1.3.1:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
hasBin: true
dependencies:
isexe: 2.0.0
dev: false
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@ -5329,6 +5791,10 @@ packages:
engines: {node: '>=10'}
dev: true
/yallist@2.1.2:
resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
dev: false
/yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}

File diff suppressed because one or more lines are too long

View file

@ -2,7 +2,7 @@
self.__dynamic$config = {
prefix: '/~/dynamic/',
encoding: 'plain',
encoding: 'aes',
mode: 'production',
logLevel: 0,
bare: {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
public/generic_globe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -3,11 +3,39 @@ importScripts("/uv/uv.config.js");
importScripts(__uv$config.sw || "/uv/uv.sw.js");
importScripts("/dynamic/dynamic.config.js");
importScripts("/dynamic/dynamic.worker.js");
//import our IDB lib
importScripts("/localforage/localforage.min.js");
localforage.config({
driver: localforage.INDEXEDDB,
name: "Nebula",
version: 1.0,
storeName: "nebula_config",
description: "Nebula Config for things reliant on IndexedDB"
});
const sw = new UVServiceWorker();
const dynamic = new Dynamic();
const dynPromise = new Promise(async (resolve) => {
try {
const bare =
(await localforage.getItem("bare")) || location.origin + "/bare/";
self.__dynamic$config.bare.path = bare;
self.dynamic = new Dynamic(self.__dynamic$config);
} catch (error) {
console.log(error);
}
resolve();
});
self.dynamic = dynamic;
const uvPromise = new Promise(async (resolve) => {
try {
const bare =
(await localforage.getItem("bare")) || location.origin + "/bare/";
self.__uv$config.bare = bare;
self.uv = new UVServiceWorker(self.__uv$config);
} catch (error) {
console.log(error);
}
resolve();
});
self.addEventListener("fetch", (event) => {
if (
@ -15,16 +43,25 @@ self.addEventListener("fetch", (event) => {
) {
event.respondWith(
(async function () {
if (await dynamic.route(event)) {
return await dynamic.fetch(event);
try {
await dynPromise;
} catch (error) {}
if (await self.dynamic.route(event)) {
return await self.dynamic.fetch(event);
}
return await fetch(event.request);
await fetch(event.request);
})()
);
} else if (
event.request.url.startsWith(location.origin + __uv$config.prefix)
event.request.url.startsWith(location.origin + self.__uv$config.prefix)
) {
event.respondWith(sw.fetch(event));
event.respondWith(
(async function () {
try {
await uvPromise;
} catch (error) {}
return await self.uv.fetch(event);
})()
);
}
});

View file

@ -0,0 +1,30 @@
@import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap");
:root {
--background-primary: #303446 !important;
--background-lighter: #292c3c !important;
--navbar-color: #292c3c !important;
--navbar-height: 60px !important;
--navbar-text-color: #c6d0f5 !important;
--navbar-link-color: #8caaee !important;
--navbar-link-hover-color: #ca9ee6 !important;
--navbar-font: "Roboto" !important;
--input-text-color: #c6d0f5 !important;
--input-placeholder-color: #a5adce !important;
--input-background-color: #232634 !important;
--input-border-color: color-mix(in srgb, #232634, #ca9ee6 50%) !important;
--input-border-size: 1.3px !important;
--navbar-logo-filter: none !important;
--dropdown-option-hover-color: #232634 !important;
--tab-color: #414559 !important;
--active-color: #ca9ee6 !important;
}
.font-inter {
font-family: "Inter", sans-serif;
font-weight: 300;
}
.font-roboto {
font-family: "Roboto";
}

View file

@ -0,0 +1,30 @@
@import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap");
:root {
--background-primary: #eff1f5 !important;
--background-lighter: #e6e9ef !important;
--navbar-color: #e6e9ef !important;
--navbar-height: 60px !important;
--navbar-text-color: #4c4f69 !important;
--navbar-link-color: #1e66f5 !important;
--navbar-link-hover-color: #8839ef !important;
--navbar-font: "Roboto" !important;
--input-text-color: #4c4f69 !important;
--input-placeholder-color: #6c6f85 !important;
--input-background-color: #dce0e8 !important;
--input-border-color: color-mix(in srgb, #dce0e8, #8839ef 50%) !important;
--input-border-size: 1.3px !important;
--navbar-logo-filter: none !important;
--dropdown-option-hover-color: #dce0e8 !important;
--tab-color: #ccd0da !important;
--active-color: #8839ef !important;
}
.font-inter {
font-family: "Inter", sans-serif;
font-weight: 300;
}
.font-roboto {
font-family: "Roboto";
}

View file

@ -0,0 +1,30 @@
@import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap");
:root {
--background-primary: #24273a !important;
--background-lighter: #1e2030 !important;
--navbar-color: #1e2030 !important;
--navbar-height: 60px !important;
--navbar-text-color: #cad3f5 !important;
--navbar-link-color: #8aadf4 !important;
--navbar-link-hover-color: #c6a0f6 !important;
--navbar-font: "Roboto" !important;
--input-text-color: #cad3f5 !important;
--input-placeholder-color: #a5adcb !important;
--input-background-color: #181926 !important;
--input-border-color: color-mix(in srgb, #181926, #c6a0f6 50%) !important;
--input-border-size: 1.3px !important;
--navbar-logo-filter: none !important;
--dropdown-option-hover-color: #181926 !important;
--tab-color: #363a4f !important;
--active-color: #c6a0f6 !important;
}
.font-inter {
font-family: "Inter", sans-serif;
font-weight: 300;
}
.font-roboto {
font-family: "Roboto";
}

View file

@ -0,0 +1,30 @@
@import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap");
:root {
--background-primary: #1e1e2e !important;
--background-lighter: #181825 !important;
--navbar-color: #181825 !important;
--navbar-height: 60px !important;
--navbar-text-color: #cdd6f4 !important;
--navbar-link-color: #89b4fa !important;
--navbar-link-hover-color: #cba6f7 !important;
--navbar-font: "Roboto" !important;
--input-text-color: #cdd6f4 !important;
--input-placeholder-color: #a6adc8 !important;
--input-background-color: #11111b !important;
--input-border-color: color-mix(in srgb, #11111b, #cba6f7 50%) !important;
--input-border-size: 1.3px !important;
--navbar-logo-filter: none !important;
--dropdown-option-hover-color: #11111b !important;
--tab-color: #313244 !important;
--active-color: #cba6f7 !important;
}
.font-inter {
font-family: "Inter", sans-serif;
font-weight: 300;
}
.font-roboto {
font-family: "Roboto";
}

View file

@ -16,6 +16,7 @@
--input-border-size: 1.3px;
--navbar-logo-filter: none;
--dropdown-option-hover-color: #312a49;
--tab-color: var(--black);
}
.font-inter {

View file

@ -1,8 +1,8 @@
self.__uv$config = {
prefix: "/~/uv/",
bare: "/bare/",
encodeUrl: Ultraviolet.codec.plain.encode,
decodeUrl: Ultraviolet.codec.plain.decode,
encodeUrl: Ultraviolet.codec.aes.encode,
decodeUrl: Ultraviolet.codec.aes.decode,
handler: "/uv/uv.handler.js",
client: "/uv/uv.client.js",
bundle: "/uv/uv.bundle.js",

View file

@ -77,6 +77,16 @@ app.register(fastifyStatic, {
wildcard: false
});
app.get("/search=:query", async (req, res) => {
const { query } = req.params as { query: string }; // Define the type for req.params
const response = await fetch(
`http://api.duckduckgo.com/ac?q=${query}&format=json`
).then((apiRes) => apiRes.json());
res.send(response);
});
app.setNotFoundHandler((req, res) => {
res.sendFile("index.html"); // SPA catch-all
});

View file

@ -8,6 +8,13 @@ export function AboutBlank(props: { url: string }) {
iframe.style.height = "100%";
iframe.style.border = "none";
iframe.style.overflow = "hidden";
iframe.style.margin = "0";
iframe.style.padding = "0";
iframe.style.position = "fixed";
iframe.style.top = "0";
iframe.style.bottom = "0";
iframe.style.left = "0";
iframe.style.right = "0";
newWindow.document.body.appendChild(iframe);
window.location.replace("https://google.com");
return (

View file

@ -1,8 +1,8 @@
import './Suspense.css'
import "./Suspense.css";
export function LoadSuspense() {
return (
<div class="suspenseContainer">
<div className="suspenseContainer">
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.2"
@ -10,7 +10,7 @@ export function LoadSuspense() {
width="400"
height="400"
fill="#5e17eb"
class="animate-pulse-brighter"
className="animate-pulse-brighter"
>
<g id="svgg">
<path

View file

@ -1,7 +1,7 @@
import { HeaderButton } from "./HeaderButton";
import { useTranslation } from "react-i18next";
import { Link } from "preact-router";
import { motion } from "framer-motion"
import { motion } from "framer-motion";
// Header icons
import { HiOutlineCube } from "react-icons/hi";
@ -14,50 +14,105 @@ export function Header() {
const [isActive, setIsActive] = useState(false);
return (
<div id="navbar" className="flex h-16 flex-row items-center justify-between bg-navbar-color px-4">
<Link href="/" class="w-1/8">
<div className="flex flex-row items-center">
<img src="/logo.png" alt="Nebula Logo" className="h-16 w-16 transition-all duration-1000 hover:rotate-[360deg]"></img>
<h1 className="font-roboto text-2xl font-bold text-navbar-text-color md:text-4xl">
{t("header.title")}
<div
id="navbar"
className="flex h-16 flex-row items-center justify-between bg-navbar-color px-4"
>
<Link href="/" className="w-1/8">
<div className="relative flex flex-row items-center">
<img
src="/logo.png"
className="h-16 w-16 transition-all duration-1000 hover:rotate-[360deg]"
alt="Nebula Logo"
></img>
<h1 className="font-roboto invisible whitespace-nowrap text-2xl font-bold text-navbar-text-color sm:visible sm:text-4xl">
{" "}
{t("header.title")}{" "}
</h1>
</div>
</Link>
<motion.button type="button" className="z-20 md:hidden text-text-color text-bold text-3xl mr-4" aria-expanded={isActive} aria-controls="navbar-default" onClick={() => setIsActive(!isActive)} initial={{ rotate: 0 }} animate={{ rotate: isActive ? 90 : 0 }} transition={{ duration: 0.5 }} >
<RxHamburgerMenu />
<motion.button
type="button"
className="text-bold z-20 mr-4 text-3xl text-text-color md:hidden"
aria-expanded={isActive}
aria-controls="navbar-default"
onClick={() => setIsActive(!isActive)}
initial={{ rotate: 0 }}
animate={{ rotate: isActive ? 90 : 0 }}
transition={{ duration: 0.5 }}
>
<RxHamburgerMenu />
</motion.button>
{window.innerWidth >= 768 &&
{window.innerWidth >= 768 && (
//standard menu
<div className={`fixed inset-0 z-10 flex md:relative md:right-0 ${ window.innerWidth <= 768 && !isActive && "hidden"}`}>
<div className="h-[calc(100%-4rem)] w-full mt-16 lg:h-full lg:mt-auto md:h-full md:mt-auto">
<div className="flex h-full w-full whitespace-nowrap" onClick={() => setIsActive(false)} >
<div className="flex w-full flex-col justify-evenly md:flex-row">
<HeaderButton href="/games" Icon={HiOutlineCube} translationKey="header.games" />
<HeaderButton href="/settings" Icon={RxMixerVertical} translationKey="header.settings" />
<HeaderButton href="/discord" Icon={RiLinksFill} translationKey="header.discord" />
</div>
</div>
<div
className={`fixed inset-0 z-10 flex md:relative md:right-0 ${
window.innerWidth <= 768 && !isActive && "hidden"
}`}
>
<div className="mt-16 h-[calc(100%-4rem)] w-full md:mt-auto md:h-full lg:mt-auto lg:h-full">
<div
className="flex h-full w-full whitespace-nowrap"
onClick={() => setIsActive(false)}
>
<div className="flex w-full flex-col justify-evenly md:flex-row">
<HeaderButton
href="/games"
Icon={HiOutlineCube}
translationKey="header.games"
/>
<HeaderButton
href="/settings"
Icon={RxMixerVertical}
translationKey="header.settings"
/>
<HeaderButton
href="/discord"
Icon={RiLinksFill}
translationKey="header.discord"
/>
</div>
</div>
</div>
</div>
}
{window.innerWidth <= 768 &&
)}
{window.innerWidth <= 768 && (
//animated mobile menu
<motion.div className={`fixed inset-0 z-10 flex md:relative md:right-0 ${ window.innerWidth <= 768 && !isActive && "hidden"}`}
initial={{ x: 0 }}
animate={{ x: isActive ? 0 : 1000 }}
transition={{ duration: 0.5 }}
>
<div className="h-[calc(100%-4rem)] w-full mt-16 lg:h-full lg:mt-auto md:h-full md:mt-auto">
<div className="flex h-full w-full whitespace-nowrap" onClick={() => setIsActive(false)} >
<div className="flex w-full flex-col justify-evenly md:flex-row">
<HeaderButton href="/games" Icon={HiOutlineCube} translationKey="header.games" />
<HeaderButton href="/settings" Icon={RxMixerVertical} translationKey="header.settings" />
<HeaderButton href="/discord" Icon={RiLinksFill} translationKey="header.discord" />
</div>
</div>
<motion.div
className={`fixed inset-0 z-10 flex md:relative md:right-0 ${
window.innerWidth <= 768 && !isActive && "hidden"
}`}
initial={{ x: 0 }}
animate={{ x: isActive ? 0 : 1000 }}
transition={{ duration: 0.5 }}
>
<div className="mt-16 h-[calc(100%-4rem)] w-full md:mt-auto md:h-full lg:mt-auto lg:h-full">
<div
className="flex h-full w-full"
onClick={() => setIsActive(false)}
>
<div className="flex w-full flex-col justify-evenly md:flex-row">
<HeaderButton
href="/games"
Icon={HiOutlineCube}
translationKey="header.games"
/>
<HeaderButton
href="/settings"
Icon={RxMixerVertical}
translationKey="header.settings"
/>
<HeaderButton
href="/discord"
Icon={RiLinksFill}
translationKey="header.discord"
/>
</div>
</div>
</div>
</motion.div>
}
)}
</div>
);
}

View file

@ -12,12 +12,10 @@ export function HeaderButton(props: HeaderButtonProps) {
const { t } = useTranslation();
return (
<Link
href={href}
className="flex h-full w-full bg-navbar-color sm:h-auto">
<div className="group flex flex-row items-center justify-center p-4 w-full border-t-2 border-solid border-navbar-text-color md:border-none">
<Link href={href} className="flex h-full w-full bg-navbar-color sm:h-auto">
<div className="group flex w-full flex-row items-center justify-center border-t-2 border-solid border-navbar-text-color p-4 md:border-none">
<Icon className="h-10 w-10 text-text-color transition duration-500 group-hover:text-text-hover-color md:h-6 md:w-6" />
<span className="font-roboto pl-1 text-text-color text-4xl text-center font-bold transition duration-500 group-hover:text-text-hover-color md:text-lg">
<span className="font-roboto pl-1 text-center text-4xl font-bold text-text-color transition duration-500 group-hover:text-text-hover-color md:text-lg">
{t(translationKey)}
</span>
</div>

View file

@ -2,10 +2,10 @@ import { Header } from "./Header";
export function HeaderRoute(props: { children: any }) {
return (
<div class="flex h-screen flex-col">
<div className="flex h-screen flex-col">
<Header />
<div class="flex-1 bg-primary">
<main class="h-full">{props.children}</main>
<div className="flex-1 bg-primary">
<main className="h-full">{props.children}</main>
</div>
</div>
);

View file

@ -1,5 +1,9 @@
import { useState } from "preact/hooks";
import { useState, useEffect } from "preact/hooks";
import CryptoJS from "crypto-js";
import { useTranslation } from "react-i18next";
import { dec } from "../../aes";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { Link } from "preact-router";
import { RiPictureInPictureExitFill, RiFullscreenFill } from "react-icons/ri";
import {
@ -8,6 +12,7 @@ import {
IoChevronForwardSharp,
IoReloadSharp
} from "react-icons/io5";
import { FaShareAlt } from "react-icons/fa";
import { FaXmark } from "react-icons/fa6";
interface ProxyFrame extends HTMLElement {
@ -15,10 +20,72 @@ interface ProxyFrame extends HTMLElement {
contentDocument: any;
}
function Clipboard(text) {
var textarea = document.createElement("textarea"); // hacky
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
textarea.setSelectionRange(0, 99999);
document.execCommand("copy");
document.body.removeChild(textarea);
}
export function IframeHeader(props: { url: string }) {
const localProxy = localStorage.getItem("proxy") || "automatic";
const { t } = useTranslation();
const share = () => {
let proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
if (localProxy === "ultraviolet" || localProxy === "automatic") {
var encodedUrl = proxyFrame.contentWindow.location.href
.replace(window.location.origin, "")
.replace(window.__uv$config.prefix, "");
//@ts-ignore
let decodedUrl = CryptoJS.AES.decrypt(
"U2FsdGVkX1" + encodedUrl,
location.origin + navigator.userAgent
).toString(CryptoJS.enc.Utf8);
Clipboard(decodedUrl);
toast(t("clipboard"));
} else {
toast("Your proxy choice doesn't support sharing.");
}
};
const [showPopout, setShowPopout] = useState(false);
const [showFullScreen, setFullScreen] = useState(false);
const [proxiedTitle, setProxiedTitle] = useState("");
const [proxiedFavicon, setProxiedFavicon] = useState("/generic_globe.png");
useEffect(() => {
const intervalFunction = () => {
let proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
if (proxyFrame) {
let faviconLink =
proxyFrame.contentDocument.querySelector("link[rel*='icon']");
if (faviconLink) {
setProxiedFavicon(faviconLink.href);
} else {
setProxiedFavicon("/generic_globe.png");
}
setProxiedTitle(proxyFrame.contentDocument.title);
} else {
console.log(
"ehhh this aint supposed to happen. no proxied iframe found."
);
}
};
const intervalId = setInterval(intervalFunction, 1000);
return () => clearInterval(intervalId);
}, []);
if (showPopout) {
window.location.replace(props.url);
@ -28,95 +95,100 @@ export function IframeHeader(props: { url: string }) {
setFullScreen(false);
}
return (
<div
id="iframeNav"
className="flex h-16 flex-row items-center justify-between gap-3 bg-navbar-color px-4"
>
<Link href="/" class="w-1/8">
<div className="flex flex-row items-center">
<img
src="/logo.png"
className="h-16 w-16 transition-all duration-1000 hover:rotate-[360deg]"
alt="Nebula Logo"
></img>
<h1 className="font-roboto text-2xl font-bold text-navbar-text-color md:text-4xl">
{" "}
{t("header.title")}{" "}
</h1>
<div>
<div
id="iframeNav"
className="flex h-16 flex-row items-center justify-between gap-3 bg-navbar-color px-4"
>
<div className="w-1/8">
<div className="flex flex-row items-center">
<img src={proxiedFavicon} className="h-12 w-12 p-2"></img>
<h1 className="font-roboto whitespace-normal text-sm font-bold text-text-color sm:visible sm:text-lg">
{proxiedTitle ? proxiedTitle : "Loading..."}
</h1>
</div>
</div>
</Link>
<div className="flex flex-row items-center gap-3 md:gap-2">
<IoChevronBackSharp
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={() => {
const proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
proxyFrame.contentWindow.history.back();
}}
/>
<IoReloadSharp
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:rotate-[360deg] hover:scale-110 hover:brightness-125"
onClick={() => {
const proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
proxyFrame.contentWindow.location.reload();
}}
/>
<IoChevronForwardSharp
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={() => {
const proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
proxyFrame.contentWindow.history.forward();
}}
/>
</div>
<div id="navItems" class="w-1/8">
<div className="mr-4 flex flex-row items-center justify-end gap-3">
<IoCodeSlashSharp
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={() => {
const proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
if (!proxyFrame) return;
<div id="navItems" className="w-1/8">
<div className="mr-4 flex flex-row items-center justify-end gap-3">
<IoChevronBackSharp
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={() => {
const proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
proxyFrame.contentWindow.history.back();
}}
/>
<IoChevronForwardSharp
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={() => {
const proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
proxyFrame.contentWindow.history.forward();
}}
/>
<IoReloadSharp
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:rotate-[360deg] hover:scale-110 hover:brightness-125"
onClick={() => {
const proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
proxyFrame.contentWindow.location.reload();
}}
/>
<FaShareAlt
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={share}
/>
<IoCodeSlashSharp
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={() => {
const proxyFrame: ProxyFrame | null = document.getElementById(
"iframe"
) as ProxyFrame;
if (!proxyFrame) return;
const proxyWindow = proxyFrame.contentWindow;
const proxyWindow = proxyFrame.contentWindow;
const proxyDocument = proxyFrame.contentDocument;
const proxyDocument = proxyFrame.contentDocument;
if (!proxyWindow || !proxyDocument) return;
if (!proxyWindow || !proxyDocument) return;
if (proxyWindow.eruda?._isInit) {
proxyWindow.eruda.destroy();
} else {
let script = proxyDocument.createElement("script");
script.src = "https://cdn.jsdelivr.net/npm/eruda";
script.onload = function () {
if (!proxyWindow) return;
proxyWindow.eruda.init();
proxyWindow.eruda.show();
};
proxyDocument.head.appendChild(script);
}
}}
/>
<RiPictureInPictureExitFill
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={() => setShowPopout(true)}
/>
<RiFullscreenFill
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125 active:rotate-90"
onClick={() => setFullScreen(true)}
/>
<Link href="/">
<FaXmark className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:rotate-[360deg] hover:scale-110 hover:brightness-125" />
</Link>
if (proxyWindow.eruda?._isInit) {
proxyWindow.eruda.destroy();
} else {
let script = proxyDocument.createElement("script");
script.src = "https://cdn.jsdelivr.net/npm/eruda";
script.onload = function () {
if (!proxyWindow) return;
proxyWindow.eruda.init({
defaults: {
displaySize: 45,
theme: "Material Palenight"
}
});
proxyWindow.eruda.show();
};
proxyDocument.head.appendChild(script);
}
}}
/>
<RiPictureInPictureExitFill
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125"
onClick={() => setShowPopout(true)}
/>
<RiFullscreenFill
className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:scale-110 hover:brightness-125 active:rotate-90"
onClick={() => setFullScreen(true)}
/>
<Link href="/">
<FaXmark className="duration-0500 h-6 w-6 cursor-pointer text-navbar-text-color transition-all hover:rotate-[360deg] hover:scale-110 hover:brightness-125" />
</Link>
</div>
</div>
</div>
<ToastContainer position="bottom-right" type="sucess" theme="dark" />
</div>
);
}

View file

@ -1,15 +1,25 @@
import { render } from "preact";
import { Suspense, lazy } from "preact/compat";
import { LoadSuspense } from "./LoadSuspense";
import { Helmet } from "react-helmet";
const Routes = lazy(() => import("./routes"));
const theme = localStorage.getItem("theme") || "main";
export default function App() {
return (
<Suspense fallback={<LoadSuspense />}>
<div>
<Routes />
</div>
</Suspense>
<div>
<Helmet>
<link rel="stylesheet" href={"/themes/" + theme + ".css"}></link>
<link rel="stylesheet" href="/themes/main.css"></link>
</Helmet>
<Suspense fallback={<LoadSuspense />}>
<div>
<Routes />
</div>
</Suspense>
</div>
);
}

View file

@ -32,10 +32,7 @@
},
"languages": {
"title": "Language",
"subtitle": "Choose your preferred language",
"japanese": "Japanese",
"english": "English",
"spanish": "Spanish"
"subtitle": "Choose your preferred language"
},
"proxymodes": {
"title": "Open in",
@ -46,11 +43,22 @@
},
"cloaking": {
"title": "Cloaking",
"subtitle": "Choose how your tab looks"
"subtitle": "Choose how your tab looks",
"aboutblank": "Open in about:blank"
},
"search": {
"title": "Search Engine",
"subtitle": "Choose your search engine"
},
"bare": {
"title": "Bare Server",
"subtitle": "Enter the URL of your bare server",
"select": "Select"
},
"theme": {
"title": "Theme",
"subtitle": "Choose a theme so your eyes don't hate us",
"select": "Select"
}
},
"titles": {
@ -59,5 +67,14 @@
"discord": "Nebula - Discord",
"404": "Nebula - 404"
},
"comingsoon": "Coming soon!"
"comingsoon": "Coming soon!",
"themes": {
"main": "Main",
"catppuccinMocha": "Catppuccin Mocha",
"catppuccinMacchiato": "Catppuccin Macchiato",
"catppuccinFrappe": "Catppuccin Frappe",
"catppuccinLatte": "Catppuccin Latte"
},
"clipboard": "URL copied to clipboard!",
"bareError": "That didn't quite work. Double check that the bare server exists and isn't blocked."
}

View file

@ -32,10 +32,7 @@
},
"languages": {
"title": "Idioma",
"subtitle": "Elige tu idioma preferido",
"japanese": "Japonés",
"english": "Inglés",
"spanish": "Español"
"subtitle": "Elige tu idioma preferido"
},
"proxymodes": {
"title": "Abrir en",
@ -46,11 +43,21 @@
},
"cloaking": {
"title": "Encubrimiento",
"subtitle": "Elige cómo se ve tu pestaña"
"subtitle": "Elige cómo se ve tu pestaña",
"aboutblank": "Abierte en about:blank"
},
"search": {
"title": "Buscador",
"subtitle": "Elige tu motor de búsqueda."
},
"bare": {
"title": "Bare Server",
"subtitle": "Pon tu url de tu bare server",
"select": "Seleccionar"
},
"theme": {
"title": "Mirar",
"subtitle": "Elige una mirada para que tus ojos no nos odienn"
}
},
"titles": {
@ -59,5 +66,14 @@
"discord": "Nebula - Discord",
"404": "Nebula - 404"
},
"comingsoon": "¡Próximamente!"
"comingsoon": "¡Próximamente!",
"themes": {
"main": "Por defecto",
"catppuccinMocha": "Catppuccin Mocha",
"catppuccinMacchiato": "Catppuccin Macchiato",
"catppuccinFrappe": "Catppuccin Frappe",
"catppuccinLatte": "Catppuccin Latte"
},
"clipboard": "¡URL copiada al portapapeles!",
"bareError": "Esto no es funcional. Vuelva a verificar que el servidor bare exista y no esté bloqueado."
}

View file

@ -1,6 +1,6 @@
{
"header": {
"title": "nebula.",
"title": "ネブラ。",
"games": "ゲーム",
"settings": "セッティング",
"discord": "もっとリンクが欲しいですか?"
@ -32,10 +32,7 @@
},
"languages": {
"title": "言語",
"subtitle": "好きな言語を選んでください",
"japanese": "日本語",
"english": "英語",
"spanish": "スペイン語"
"subtitle": "好きな言語を選んでください"
},
"proxymodes": {
"title": "開く",
@ -46,11 +43,21 @@
},
"cloaking": {
"title": "クローキング",
"subtitle": "タブの見た目を選択する"
"subtitle": "タブの見た目を選択する",
"aboutblank": "で開く about:blank"
},
"search": {
"title": "検索エンジン",
"subtitle": "ネビュラの検索エンジンを選択してください"
},
"bare": {
"title": "Bare サーバー",
"subtitle": "Bare サーバー URL を入力してください",
"select": "選択する"
},
"theme": {
"title": "テーマ",
"subtitle": "目が嫌いにならないようにテーマを選んでください"
}
},
"titles": {
@ -59,5 +66,14 @@
"discord": "ネブラ - Discord",
"404": "ネブラ - 404"
},
"comingsoon": "近日公開"
"comingsoon": "近日公開",
"themes": {
"main": "デフォルト",
"catppuccinMocha": "Catppuccin Mocha",
"catppuccinMacchiato": "Catppuccin Macchiato",
"catppuccinFrappe": "Catppuccin Frappe",
"catppuccinLatte": "Catppuccin Latte"
},
"clipboard": "URL がクリップボードにコピーされました!",
"bareError": "それはうまくいきませんでした。Bare サーバーが存在し、ブロックされていないことを再確認してください。"
}

View file

@ -1,13 +1,91 @@
import { useState } from "preact/hooks";
import { useTranslation } from "react-i18next";
import { HeaderRoute } from "../components/HeaderRoute";
import { set } from "../util/IDB";
import { uninstallServiceWorkers } from "../util/SWHelper";
import prod from "./config.json"; // Set prod to true if you wish to load balance
import { enc } from "../aes";
import CloakedHead from "../util/CloakedHead";
import { useEffect } from "preact/hooks";
export function Home() {
const [isFocused, setIsFocused] = useState(false);
const [showSuggestions, setShowSuggestions] = useState(false);
const [inputValue, setInputValue] = useState("");
const [suggestions, setSuggestions] = useState([]);
useEffect(() => {
const handleLoad = () => {
const firstLoad = localStorage.getItem("firstLoad") || "true";
console.log(firstLoad);
if (firstLoad == "true" && prod) {
function changeBare(url: string) {
set("bare", url);
localStorage.setItem("bare", url);
uninstallServiceWorkers();
window.location.reload();
}
async function test() {
const nonProtocolOrigin = window.location.origin.replace(
/^https?:\/\//,
""
);
// Do Tokyo-US pinging to find optimal server
const ping = async (url: string) => {
let start = Date.now();
await fetch(url);
let end = Date.now();
let total = end - start;
return total;
};
const usUrl = "https://us." + nonProtocolOrigin;
const jpUrl = "https://jp." + nonProtocolOrigin;
console.log(usUrl, jpUrl)
const [usTime, jpTime] = await Promise.all([
ping(usUrl),
ping(jpUrl)
]);
if (usTime < jpTime) {
console.log("US faster");
changeBare(usUrl);
} else {
console.log("Japan faster");
changeBare(jpUrl);
}
localStorage.setItem("firstLoad", "false");
}
test();
}
};
window.addEventListener("load", handleLoad);
return () => window.removeEventListener("load", handleLoad);
}, []);
const { t } = useTranslation();
const handleInputChange = async (event) => {
setInputValue((event.target as HTMLInputElement).value);
const newQuery = event.target.value;
setInputValue(newQuery);
const response = await fetch(`/search=${newQuery}`).then((res) =>
res.json()
);
const newSuggestions = response?.map((item) => item.phrase) || [];
setSuggestions(newSuggestions);
};
const handleSubmit = (event) => {
event.preventDefault();
window.location.href =
@ -27,36 +105,80 @@ export function Home() {
originalTitle={t("titles.home")}
originalFavicon="/logo.png"
/>
<div class="flex h-full flex-col items-center justify-center">
<div class="font-inter absolute bottom-0 left-0 p-4 text-sm italic text-input-text">
<div className="flex h-full flex-col items-center justify-center">
<div className="font-inter absolute bottom-0 left-0 p-4 text-sm italic text-input-text">
Nebula &copy; Nebula Services {new Date().getUTCFullYear()}
</div>
<a href="https://github.com/NebulaServices/Nebula">
<div class="font-inter absolute bottom-0 right-0 p-4 text-sm text-input-text">
<div className="font-inter absolute bottom-0 right-0 p-4 text-sm text-input-text">
GitHub
</div>
</a>
<form
onSubmit={handleSubmit}
class="flex h-full w-full items-center justify-center"
className="flex h-full w-full flex-col items-center justify-center"
>
<input
onFocus={() => {
setShowSuggestions(true);
setIsFocused(true);
}}
onBlur={() => {
setIsFocused(false);
setTimeout(() => {
setShowSuggestions(false); // delay so the user has time to click suggestions
}, 200);
}}
type="text"
value={inputValue}
onChange={(e) =>
setInputValue((e.target as HTMLInputElement).value)
}
className={`font-roboto h-14 rounded-2xl border border-input-border-color bg-input p-2 text-center text-xl placeholder:text-input-text focus:outline-none ${
isFocused ? "w-10/12 md:w-3/12" : "w-80"
onChange={handleInputChange}
className={`font-roboto h-14 rounded-t-2xl border border-input-border-color bg-input p-2 text-center text-xl text-input-text placeholder:text-input-text focus:outline-none ${
isFocused && inputValue.trim() !== ""
? "w-10/12 md:w-3/12"
: "w-80 rounded-2xl"
} transition-all duration-300`}
placeholder={isFocused ? "" : t("home.placeholder")}
/>
<div className="relative flex w-10/12 flex-col items-center md:w-3/12">
<div className="absolute w-full text-center">
{showSuggestions &&
suggestions.map((suggestion, index) => (
<a
href={
"/go/" +
encodeURIComponent(
//@ts-ignore
enc(
suggestion,
window.location.origin.slice(8) + navigator.userAgent
).substring(10)
)
}
>
<div
className={`font-roboto w-110 flex h-10 flex-none shrink-0 items-center justify-center border border-input-border-color bg-input p-2 text-xl hover:bg-dropdown-option-hover-color ${
index === suggestions.length - 1 ? "rounded-b-2xl" : ""
}`}
key={index}
>
{suggestion}
</div>
</a>
))}
{/* {showSuggestions &&
Array.from({ length: 10 }, (_, index) => (
<div
key={index}
className="font-roboto w-110 hover:bg-dropdown-option-hover-colo flex h-8 flex-none shrink-0 items-center justify-center border border-input-border-color p-2 text-2xl"
>
Example suggestion
</div>
))}
*/}
</div>
</div>
</form>
</div>
</HeaderRoute>

View file

@ -22,7 +22,7 @@ export function ProxyFrame(props: { url: string }) {
const localProxy = localStorage.getItem("proxy") || "automatic";
const proxyMode = localStorage.getItem("proxyMode") || "embed";
const searchEngine =
localStorage.getItem("searchEngine") || "https://google.com/search?q=%s";
localStorage.getItem("searchEngine") || "https://duckduckgo.com/?q=%s";
const [ProxiedUrl, setProxiedUrl] = useState<string | undefined>(undefined);
//@ts-ignore
@ -47,7 +47,9 @@ export function ProxyFrame(props: { url: string }) {
window.__uv$config.encodeUrl(decodedUrl);
} else if (localProxy === "dynamic") {
result =
window.__dynamic$config.prefix + encodeURIComponent(decodedUrl);
window.__dynamic$config.prefix +
"route?url=" +
encodeURIComponent(decodedUrl);
} else {
// automatic. use SiteSupport.json to determine proxy support
const matchingKey = Object.keys(SiteSupport).find((key) =>
@ -60,7 +62,9 @@ export function ProxyFrame(props: { url: string }) {
window.__uv$config.encodeUrl(decodedUrl);
} else if (SiteSupport[matchingKey] === "dynamic") {
result =
window.__dynamic$config.prefix + encodeURIComponent(decodedUrl);
window.__dynamic$config.prefix +
"route?url=" +
encodeURIComponent(decodedUrl);
} else if (SiteSupport[matchingKey] === "rammerhead") {
result = await RammerheadEncode(decodedUrl);
} else {
@ -93,8 +97,12 @@ export function ProxyFrame(props: { url: string }) {
window.location.href = ProxiedUrl;
}
if (proxyMode === "embed") {
history.pushState({}, "", "/");
}
return (
<div class="h-screen w-screen bg-primary">
<div className="h-screen w-screen bg-primary">
<CloakedHead
originalTitle={t("titles.home")}
originalFavicon="/logo.png"

View file

@ -1,9 +1,17 @@
import { HeaderRoute } from "../components/HeaderRoute";
interface Window {
__uv$config: any;
}
export function Radon() {
return (
<HeaderRoute>
<iframe src="/~/uv/https%3A%2F%2Fradon.games%2F" class="w-full h-full"></iframe>
<iframe
src={
window.__uv$config.prefix +
window.__uv$config.encodeUrl("https://radon.games")
}
className="h-full w-full"
></iframe>
</HeaderRoute>
)
);
}

View file

@ -0,0 +1,84 @@
import { useState, useEffect } from "preact/hooks";
import { set } from "../../util/IDB";
import { uninstallServiceWorkers } from "../../util/SWHelper";
import { useTranslation } from "react-i18next";
import { ToastContainer, toast } from "react-toastify";
import { BareTest } from "./BareTest";
interface BareInputProps {
placeholder: string;
storageKey: string;
}
function BareInput(props: BareInputProps) {
const { t } = useTranslation();
const value = localStorage.getItem(props.storageKey) || "/bare/";
const [inputValue, setInputValue] = useState(value);
function validateUrl(url: string) {
let finalUrl = url;
if (url === "/bare/" || url === "/bare") {
finalUrl = "/bare/";
return finalUrl;
}
if (url === null || url === undefined || url === "") {
finalUrl = "/bare/";
return finalUrl;
}
if (!url.endsWith("/")) {
finalUrl = url + "/";
}
if (!finalUrl.startsWith("http://") && !finalUrl.startsWith("https://")) {
finalUrl = "https://" + finalUrl;
}
return finalUrl;
}
function handleChange() {
const url = validateUrl(
(document.getElementById("input") as HTMLInputElement).value
);
BareTest(url + "v3/").then((result) => {
if (result) {
setInputValue(
(document.getElementById("input") as HTMLInputElement).value
);
set(props.storageKey, url);
localStorage.setItem(props.storageKey, url);
uninstallServiceWorkers();
window.location.reload();
} else {
(document.getElementById("input") as HTMLInputElement).value =
localStorage.getItem("bare") || "/bare/";
toast(t("bareError"), {
type: "error"
});
}
});
}
return (
<div>
<ToastContainer position="bottom-right" theme="dark" />
<div className="flex flex-col items-center">
<input
type="text"
placeholder={props.placeholder}
value={inputValue}
onKeyPress={(event) => {
if (event.key === "Enter") {
handleChange()
}
}}
id="input"
className="font-roboto flex h-14 w-56 flex-row rounded-2xl border border-input-border-color bg-input p-4 text-center text-xl"
/>
<div
className="font-roboto mt-2 flex h-4 w-36 cursor-pointer flex-row items-center justify-center rounded-xl border border-input-border-color bg-input p-5 text-center text-lg"
onClick={handleChange}
>
{t("settings.bare.select")}
</div>
</div>
</div>
);
}
export default BareInput;

View file

@ -0,0 +1,29 @@
export function BareTest(bareUrl) {
const headers = new Headers({
"x-bare-url": "https://www.google.com",
"X-Bare-Headers": JSON.stringify({
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
})
});
return fetch(bareUrl, {
method: "GET",
headers: headers
})
.then((response) => {
if (
response.headers.get("x-bare-status") === "200" ||
response.headers.get("x-bare-status") === "302"
) {
return true;
} else {
// the site is a real site but doesn't act like a bare server
return false;
}
})
.catch((error) => {
// incase the site doesn't exist
return false;
});
}

View file

@ -17,11 +17,11 @@ const CloakPreset = (props: Props) => {
return (
<div
onClick={cloak}
class="cursor-pointer rounded-full border border-input-border-color bg-lighter"
className="cursor-pointer rounded-full border border-input-border-color bg-lighter"
>
<img
src={props.faviconUrl === "none" ? "/logo.png" : props.faviconUrl}
class="h-16 w-16 p-4"
className="h-16 w-16 p-4"
/>
</div>
);

View file

@ -1,9 +1,19 @@
import { motion } from "framer-motion";
import { tabContentVariant, settingsPageVariant } from "./Variants";
import { useTranslation } from "react-i18next";
import Dropdown from "./Dropdown";
function Customization({ id, active }) {
const { t } = useTranslation();
const themes = [
{ id: "main", label: t("themes.main") },
{ id: "catppuccinMocha", label: t("themes.catppuccinMocha") },
{ id: "catppuccinMacchiato", label: t("themes.catppuccinMacchiato") },
{ id: "catppuccinFrappe", label: t("themes.catppuccinFrappe") },
{ id: "catppuccinLatte", label: t("themes.catppuccinLatte") }
];
return (
<motion.div
role="tabpanel"
@ -17,8 +27,15 @@ function Customization({ id, active }) {
variants={settingsPageVariant}
className="content-card flex w-full flex-col items-center justify-center text-center"
>
<img src="/comingsoonsnake.png" class="h-72 w-72"></img>
<h1 class="font-roboto text-3xl">{t("comingsoon")}</h1>
<div className="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-2 text-center">
<div className="p-2 text-3xl font-bold text-input-text">
{t("settings.theme.title")}
</div>
<div className="text-md p-4 font-bold text-input-text">
{t("settings.theme.subtitle")}
</div>
<Dropdown storageKey="theme" options={themes} refresh={true} />
</div>
</motion.div>
</motion.div>
);

View file

@ -35,11 +35,11 @@ const Dropdown = ({
onClick={() => setIsOpen(!isOpen)}
>
<div className="flex h-full w-full select-none flex-row items-center">
<div class="h-full w-1/4"></div>
<div class="flex w-2/4 flex-col items-center">
<div className="h-full w-1/4"></div>
<div className="flex w-2/4 flex-col items-center text-input-text">
{options.find((o) => o.id === choice)?.label}
</div>
<div class="flex w-1/4 flex-col items-center">
<div className="flex w-1/4 flex-col items-center text-input-text">
<FaAngleDown />
</div>
</div>
@ -48,7 +48,7 @@ const Dropdown = ({
{options.map((option, index) => (
<div
key={option.id}
className={`border border-input-border-color bg-input p-2 hover:bg-dropdown-option-hover-color ${
className={`border border-input-border-color bg-input p-2 text-input-text hover:bg-dropdown-option-hover-color ${
index === options.length - 1 ? "rounded-b-2xl" : ""
}`}
onClick={() => {

View file

@ -7,9 +7,9 @@ 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") }
{ id: "en-US", label: "English" },
{ id: "es", label: "Español" },
{ id: "ja", label: "日本語" }
];
return (
@ -23,11 +23,15 @@ const Misc = ({ id, active }) => {
>
<motion.div
variants={settingsPageVariant}
className="content-card flex flex-row flex-wrap justify-center w-full gap-4"
className="content-card flex w-full flex-row flex-wrap justify-center gap-4"
>
<div class="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-7 text-center">
<div class="text-3xl">{t("settings.languages.title")}</div>
<div class="text-md">{t("settings.languages.subtitle")}</div>
<div className="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-7 text-center">
<div className="text-3xl font-bold text-input-text">
{t("settings.languages.title")}
</div>
<div className="text-md font-bold text-input-text">
{t("settings.languages.subtitle")}
</div>
<Dropdown
storageKey="i18nextLng"
options={languages}

View file

@ -1,6 +1,7 @@
import { motion } from "framer-motion";
import { tabContentVariant, settingsPageVariant } from "./Variants";
import Dropdown from "./Dropdown";
import BareInput from "./BareInput";
import { useTranslation } from "react-i18next";
const Proxy = ({ id, active }) => {
@ -20,9 +21,9 @@ const Proxy = ({ id, active }) => {
];
const searchEngines = [
{ id: "https://duckduckgo.com/?q=%s", label: "DuckDuckGo" },
{ id: "https://google.com/search?q=%s", label: "Google" },
{ id: "https://bing.com/search?q=%s", label: "Bing" },
{ id: "https://duckduckgo.com/?q=%s", label: "DuckDuckGo" }
{ id: "https://bing.com/search?q=%s", label: "Bing" }
];
return (
@ -38,29 +39,50 @@ const Proxy = ({ id, active }) => {
variants={settingsPageVariant}
className="content-card flex w-full flex-row flex-wrap justify-center gap-4"
>
<div class="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-7 text-center">
<div class="p-2 text-3xl">{t("settings.proxy.title")}</div>
<div class="text-md p-4">{t("settings.proxy.subtitle")}</div>
<div className="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-2 text-center">
<div className="p-2 text-3xl font-bold text-input-text">
{t("settings.proxy.title")}
</div>
<div className="text-md p-4 font-bold text-input-text">
{t("settings.proxy.subtitle")}
</div>
<Dropdown storageKey="proxy" options={engines} refresh={false} />
</div>
<div class="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-7 text-center">
<div class="p-2 text-3xl">{t("settings.proxymodes.title")}</div>
<div class="text-md p-4">{t("settings.proxymodes.subtitle")}</div>
<div className="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-2 text-center">
<div className="p-2 text-3xl font-bold text-input-text">
{t("settings.proxymodes.title")}
</div>
<div className="text-md p-4 font-bold text-input-text">
{t("settings.proxymodes.subtitle")}
</div>
<Dropdown
storageKey="proxyMode"
options={proxyModes}
refresh={false}
/>
</div>
<div class="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-7 text-center">
<div class="p-2 text-3xl">{t("settings.search.title")}</div>
<div class="text-md p-4">{t("settings.search.subtitle")}</div>
<div className="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-2 text-center">
<div className="p-2 text-3xl font-bold text-input-text">
{t("settings.search.title")}
</div>
<div className="text-md p-4 font-bold text-input-text">
{t("settings.search.subtitle")}
</div>
<Dropdown
storageKey="searchEngine"
options={searchEngines}
refresh={false}
/>
</div>
<div className="flex h-64 w-80 flex-col flex-wrap content-center items-center rounded-lg border border-input-border-color bg-lighter p-2 text-center">
<div className="p-2 text-3xl font-bold text-input-text">
{t("settings.bare.title")}
</div>
<div className="text-md p-4 font-bold text-input-text">
{t("settings.bare.subtitle")}
</div>
<BareInput placeholder="/bare/" storageKey="bare" />
</div>
</motion.div>
</motion.div>
);

View file

@ -69,14 +69,17 @@ const TabComponent = ({ tabs, defaultIndex = 0 }) => {
const { t } = useTranslation();
return (
<div class="flex h-full w-full flex-col items-center">
<div className="flex h-full w-full flex-col items-center">
<div className="container h-full w-full">
<div className="tabs-component">
<ul className="tab-links" role="tablist">
{tabs.map((tab, index) => (
<motion.li
key={tab.id}
className={cn("tab", { active: activeTabIndex === index })}
className={
"flex h-12 flex-row " +
cn("tab", { active: activeTabIndex === index })
}
role="presentation"
variants={tabVariant}
animate={activeTabIndex === index ? "active" : "inactive"}

View file

@ -2,6 +2,7 @@ import { motion } from "framer-motion";
import { tabContentVariant, settingsPageVariant } from "./Variants";
import CloakPreset from "./CloakPreset";
import { useTranslation } from "react-i18next";
import { LoadSuspense } from "../../LoadSuspense";
const TabSettings = ({ id, active }) => {
const { t } = useTranslation();
@ -19,9 +20,13 @@ const TabSettings = ({ id, active }) => {
variants={settingsPageVariant}
className="content-card flex w-full flex-col items-center justify-center text-center"
>
<div class="text-3xl">{t("settings.cloaking.title")}</div>
<div class="text-md pb-5">{t("settings.cloaking.subtitle")}</div>
<div class="flex flex-row space-x-4">
<div className="text-3xl font-bold text-input-text">
{t("settings.cloaking.title")}
</div>
<div className="text-md pb-5 font-bold text-input-text">
{t("settings.cloaking.subtitle")}
</div>
<div className="flex flex-row space-x-4">
<CloakPreset faviconUrl="none" title="none" />
<CloakPreset
faviconUrl="https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://google.com&size=32"
@ -39,6 +44,40 @@ const TabSettings = ({ id, active }) => {
faviconUrl="https://ssl.gstatic.com/classroom/ic_product_classroom_144.png"
title="Home"
/>
<CloakPreset
faviconUrl="https://asset-cdn.schoology.com/sites/all/themes/schoology_theme/favicon.ico"
title="Schoology"
/>
</div>
<div className="relative p-4">
<button
className="font-roboto h-14 w-56 rounded-2xl border border-input-border-color bg-input p-2 text-center text-xl font-bold text-input-text placeholder:text-input-text focus:outline-none"
onClick={() => {
let newWindow = window.open("about:blank");
let iframe = document.createElement("iframe");
iframe.src = window.location.origin;
iframe.style.width = "100%";
iframe.style.height = "100%";
iframe.style.border = "none";
iframe.style.overflow = "hidden";
iframe.style.margin = "0";
iframe.style.padding = "0";
iframe.style.position = "fixed";
iframe.style.top = "0";
iframe.style.bottom = "0";
iframe.style.left = "0";
iframe.style.right = "0";
newWindow.document.body.appendChild(iframe);
window.location.replace("https://google.com");
return (
<div>
<LoadSuspense />
</div>
);
}}
>
{t("settings.cloaking.aboutblank")}
</button>
</div>
</motion.div>
</motion.div>

View file

@ -1,3 +1,4 @@
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap");
* {
box-sizing: border-box;
}
@ -11,7 +12,7 @@
body {
-webkit-font-smoothing: antialiased;
font-family: Arial, Helvetica, sans-serif;
font-family: Roboto;
background: var(--active-color);
transition: background 1.5s ease;
}
@ -62,7 +63,7 @@ img {
height: 30px;
width: 30px;
min-width: 30px;
fill: var(--black);
fill: var(--tab-color);
transition: fill 0.5s ease;
}

View file

@ -12,15 +12,15 @@ export function NotFound() {
originalTitle={t("titles.404")}
originalFavicon="/logo.png"
/>
<section class="h-full">
<div class="flex h-full flex-col items-center justify-center">
<img src="/404.png" class="h-72"></img>
<div class="flex flex-col items-center p-6">
<p class="font-roboto text-4xl font-bold">{t("404.text")}</p>
<span class="font-roboto text-3xl">404</span>
<section className="h-full">
<div className="flex h-full flex-col items-center justify-center">
<img src="/404.png" className="h-72"></img>
<div className="flex flex-col items-center p-6">
<p className="font-roboto text-4xl font-bold">{t("404.text")}</p>
<span className="font-roboto text-3xl">404</span>
</div>
<Link href="/">
<button class="font-roboto h-14 w-44 rounded-2xl border border-input-border-color bg-input p-2 text-center text-xl placeholder:text-input-text focus:outline-none">
<button className="font-roboto h-14 w-44 rounded-2xl border border-input-border-color bg-input p-2 text-center text-xl placeholder:text-input-text focus:outline-none">
{t("404.return")}
</button>
</Link>

3
src/pages/config.json Normal file
View file

@ -0,0 +1,3 @@
{
"prod": false
}

View file

@ -11,23 +11,31 @@ export function DiscordPage() {
originalTitle={t("titles.discord")}
originalFavicon="/logo.png"
/>
<section class="h-full">
<div class="flex h-full flex-col items-center justify-center">
<img src="/services.png" class="h-72 w-72"></img>
<div class="flex flex-col items-center p-6">
<p class="font-roboto text-4xl font-bold">{t("discord.title")}</p>
<span class="font-roboto text-3xl">{t("discord.sub")}</span>
<section className="h-full">
<div className="flex h-full flex-col items-center justify-center">
<img src="/services.png" className="h-72 w-72"></img>
<div className="flex flex-col items-center p-6">
<p className="font-roboto text-4xl font-bold text-input-text">
{t("discord.title")}
</p>
<span className="font-roboto text-3xl text-input-text">
{t("discord.sub")}
</span>
</div>
<a href="https://discord.gg/unblocker" class="p-6">
<button class="font-roboto h-14 w-56 rounded-2xl border border-input-border-color bg-input p-2 text-center text-xl placeholder:text-input-text focus:outline-none">
<a href="https://discord.gg/unblocker" className="p-6">
<button className="font-roboto h-14 w-56 rounded-2xl border border-input-border-color bg-input p-2 text-center text-xl text-input-text placeholder:text-input-text focus:outline-none">
{t("discord.button1")}
</button>
</a>
<a
href="/~/uv/https%3A%2F%2Fdiscord.com%2Finvite%2Funblocker"
class="p-6"
onClick={() => {
window.location.href =
window.__uv$config.prefix +
window.__uv$config.encodeUrl("https://discord.gg/unblocker");
}}
className="p-6"
>
<button class="font-roboto h-14 w-56 rounded-2xl border border-input-border-color bg-input p-2 text-center text-xl placeholder:text-input-text focus:outline-none">
<button className="font-roboto h-14 w-56 rounded-2xl border border-input-border-color bg-input p-2 text-center text-xl text-input-text placeholder:text-input-text focus:outline-none">
{t("discord.button2")}
</button>
</a>

View file

@ -6,8 +6,8 @@ import { ProxyFrame } from "./pages/ProxyFrame.js";
import { Radon } from "./pages/Radon";
import { Settings } from "./pages/Settings/";
import { AboutBlank } from "./AboutBlank";
import "./style.css";
import "./themes/main.css";
import "./i18n";
export default function Routes() {
@ -25,4 +25,3 @@ export default function Routes() {
</LocationProvider>
);
}

22
src/util/IDB.js Normal file
View file

@ -0,0 +1,22 @@
function set(key, value) {
localforage.config({
driver: localforage.INDEXEDDB,
name: "Nebula",
version: 1.0,
storeName: "nebula_config",
description: "Nebula Config for things reliant on IndexedDB"
});
localforage.setItem(key, value);
}
async function get(key) {
localforage.config({
driver: localforage.INDEXEDDB,
name: "Nebula",
version: 1.0,
storeName: "nebula_config",
description: "Nebula Config for things reliant on IndexedDB"
});
return await localforage.getItem(key);
}
export { set, get };

19
src/util/SWHelper.js Normal file
View file

@ -0,0 +1,19 @@
function updateServiceWorkers() {
navigator.serviceWorker.getRegistrations().then(function (registrations) {
for (let registration of registrations) {
registration.update();
console.log("Service Worker Updated");
}
});
}
function uninstallServiceWorkers() {
navigator.serviceWorker.getRegistrations().then(function (registrations) {
for (let registration of registrations) {
registration.unregister();
console.log("Service Worker Unregistered");
}
});
}
export { updateServiceWorkers, uninstallServiceWorkers };

View file

@ -5,6 +5,6 @@
"example.com": "ultraviolet",
"spotify.com": "dynamic",
"spotify.link": "dynamic",
"youtube.com": "dynamic",
"youtu.be": "dynamic"
"youtube.com": "ultraviolet",
"youtu.be": "ultraviolet"
}

View file

@ -6,6 +6,7 @@
"noEmit": true,
"jsx": "react-jsx",
"jsxImportSource": "preact",
"esModuleInterop": true,
"skipLibCheck": true,
"paths": {}
}

View file

@ -2,7 +2,12 @@ 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";
import { uvPath } from "@nebula-services/ultraviolet";
import { dynamicPath } from "@nebula-services/dynamic";
import path from "path";
const __dirname = path.resolve();
console.log(dynamicPath);
export default defineConfig({
plugins: [
@ -13,6 +18,20 @@ export default defineConfig({
src: `${uvPath}/uv.*.js`.replace(/\\/g, "/"),
dest: "uv",
overwrite: false
},
{
// .replace fixes weird paths on Windows
src: `${dynamicPath}/dynamic.*.js`.replace(/\\/g, "/"),
dest: "dynamic",
overwrite: false
},
{
src: `${__dirname}/node_modules/localforage/dist/localforage.*.js`.replace(
/\\/g,
"/"
),
dest: "localforage",
overwrite: false
}
]
}),