Compare commits
335 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
218155a00b | ||
|
|
58e7cb118e | ||
|
|
cef106b512 | ||
|
|
3d45aa6e66 | ||
|
|
27c2c42df8 | ||
|
|
0f9befb6a6 | ||
|
|
10ac39b46f | ||
|
|
5fc3995257 | ||
|
|
a05e112de9 | ||
|
|
b0760dd553 | ||
|
|
a4efd90c0d | ||
|
|
18540bf5c9 | ||
|
|
8ac7847122 | ||
|
|
960863a5a2 | ||
|
|
f7ad2e3ba0 | ||
|
|
c819bce83e | ||
|
|
6d4c10dc21 | ||
|
|
7038f5f9ec | ||
|
|
b6850af1ca | ||
|
|
900d5e6272 | ||
|
|
7dafacc43c | ||
|
|
f0dd3c9e46 | ||
|
|
8e05734ee6 | ||
|
|
3005c96139 | ||
|
|
4ad7ae80cd | ||
|
|
4cef641dbd | ||
|
|
95c2bb0ae6 | ||
|
|
4ce7d5a065 | ||
|
|
9a48ae3416 | ||
|
|
7526623ce0 | ||
|
|
859d84969f | ||
|
|
8d0d1d1116 | ||
|
|
0ad5812cd3 | ||
|
|
4b6614f952 | ||
|
|
7be231fa31 | ||
|
|
e1d17b9345 | ||
|
|
6f85fafa6a | ||
|
|
3efee9b98d | ||
|
|
f2839a035d | ||
|
|
9f0bf7c32b | ||
|
|
a921fbe4ad | ||
|
|
237038cdea | ||
|
|
b3c04f1227 | ||
|
|
216d93c429 | ||
|
|
be7edf5fcc | ||
|
|
075ae062db | ||
|
|
f6658cf533 | ||
|
|
fc65ac0b9b | ||
|
|
97757441d8 | ||
|
|
1b3f2c4ffd | ||
|
|
b24b097994 | ||
|
|
7da9869597 | ||
|
|
acf34d732d | ||
|
|
0339060ae9 | ||
|
|
791c74672e | ||
|
|
268ba43869 | ||
|
|
341565236f | ||
|
|
1dc6481706 | ||
|
|
d83770ce3a | ||
|
|
807064fa2f | ||
|
|
e849ea895f | ||
|
|
20b7be723a | ||
|
|
064916b3b4 | ||
|
|
623e30cc0b | ||
|
|
4d28b54ced | ||
|
|
eaa683a77e | ||
|
|
bb5516af4e | ||
|
|
53a92c0016 | ||
|
|
26ffd13f2b | ||
|
|
b365acb7cc | ||
|
|
ec0171f0a4 | ||
|
|
ea226a01ff | ||
|
|
193cccecaa | ||
|
|
a9866208b4 | ||
|
|
0c74bc1353 | ||
|
|
008da91719 | ||
|
|
0430b040d0 | ||
|
|
c4e16dd2a6 | ||
|
|
0e5c6af2b9 | ||
|
|
d2b8adc40c | ||
|
|
025d2c58ae | ||
|
|
96267e5878 | ||
|
|
e02e5f1cfc | ||
|
|
e3f1f1e4f0 | ||
|
|
e7f7ac68dc | ||
|
|
87504ad409 | ||
|
|
b0ae707ce2 | ||
|
|
0765072ea2 | ||
|
|
255488ad16 | ||
|
|
6e06134b77 | ||
|
|
2f5a65cc3e | ||
|
|
26797b6ee6 | ||
|
|
e0a8eb0dd4 | ||
|
|
ad2cbbc98a | ||
|
|
8332c191d2 | ||
|
|
92f23fb7c6 | ||
|
|
4674bd182e | ||
|
|
554c3a695d | ||
|
|
73077c7565 | ||
|
|
2fc7f56b47 | ||
|
|
f2fcf29317 | ||
|
|
6754ab22da | ||
|
|
977f723614 | ||
|
|
88fa88c623 | ||
|
|
e6b1d52987 | ||
|
|
d41b427266 | ||
|
|
5a48e2d71e | ||
|
|
ab3049dd84 | ||
|
|
311a8e649e | ||
|
|
af4856498c | ||
|
|
2a127f06e2 | ||
|
|
415841ee35 | ||
|
|
e4e4bbee09 | ||
|
|
b617851141 | ||
|
|
2365bc19dc | ||
|
|
14d2f8e956 | ||
|
|
90e5bbb7f2 | ||
|
|
33e80ef1eb | ||
|
|
e7aa57adcb | ||
|
|
0fe23c7020 | ||
|
|
09914ab8f7 | ||
|
|
900a604f5a | ||
|
|
55a0c620b4 | ||
|
|
954c375a5f | ||
|
|
8cb071bb0b | ||
|
|
8e847df600 | ||
|
|
850977b6ec | ||
|
|
ae0177959f | ||
|
|
2254f6e639 | ||
|
|
f761393a99 | ||
|
|
3806d64f66 | ||
|
|
622855db01 | ||
|
|
aaa6334561 | ||
|
|
1da4dd3ec9 | ||
|
|
adab5005ad | ||
|
|
5eb2ec5f6e | ||
|
|
92952437d8 | ||
|
|
1e094d1a79 | ||
|
|
00ed3fe3b4 | ||
|
|
67e7fcf72d | ||
|
|
a3a9f2c84f | ||
|
|
2ff4ed096c | ||
|
|
bd1f8c6ced | ||
|
|
4823932aea | ||
|
|
00ed00b0d9 | ||
|
|
6aec8c3e3f | ||
|
|
69881c3dd7 | ||
|
|
993564ed24 | ||
|
|
66ba68f479 | ||
|
|
deb9193b9a | ||
|
|
6a3b062644 | ||
|
|
35c167503d | ||
|
|
8faa1c147a | ||
|
|
76c5560449 | ||
|
|
c9843beae5 | ||
|
|
eb94275c94 | ||
|
|
07b0255a01 | ||
|
|
29177bbfac | ||
|
|
f1dc7c91a7 | ||
|
|
04952867ef | ||
|
|
213c729a70 | ||
|
|
0a4a32974f | ||
|
|
e5da668e59 | ||
|
|
7e3d3c1a0d | ||
|
|
65de29cd92 | ||
|
|
021b314e6b | ||
|
|
c3e17ea81a | ||
|
|
4579865ee4 | ||
|
|
67d9de5adc | ||
|
|
fe8833e4ec | ||
|
|
033feebb14 | ||
|
|
160e043181 | ||
|
|
839d23d104 | ||
|
|
10d1a84d9c | ||
|
|
3745c0cec5 | ||
|
|
d66fcbdf65 | ||
|
|
1a2d0cccf7 | ||
|
|
aae94e6275 | ||
|
|
dda3ee5ee6 | ||
|
|
62b9925767 | ||
|
|
ed4714bd16 | ||
|
|
529f6d6086 | ||
|
|
82cb084744 | ||
|
|
fc77fccc55 | ||
|
|
6953527d2a | ||
|
|
5371feea2d | ||
|
|
d58e31e8d9 | ||
|
|
e9167fda9a | ||
|
|
8cc6dc57fc | ||
|
|
bc34a6a85c | ||
|
|
b6b86e4f2f | ||
|
|
eee76b356c | ||
|
|
df248d213c | ||
|
|
4b75efbddd | ||
|
|
9d74ddf394 | ||
|
|
b9f64617dd | ||
|
|
6f4f234c82 | ||
|
|
4395c41041 | ||
|
|
118d62f392 | ||
|
|
9e0360cb2b | ||
|
|
aac5e5feb7 | ||
|
|
b04d3f8b41 | ||
|
|
597492b387 | ||
|
|
e54b1c9b21 | ||
|
|
9d7630bb5e | ||
|
|
3444c98bf3 | ||
|
|
1a47676a9e | ||
|
|
94e30e9925 | ||
|
|
e42e83e3a9 | ||
|
|
bea33a22c6 | ||
|
|
9bc3473bc7 | ||
|
|
688d871c15 | ||
|
|
a88c5993b0 | ||
|
|
d9113c3c13 | ||
|
|
c0ea8fda4d | ||
|
|
fb2b77f4d9 | ||
|
|
d25112f5e2 | ||
|
|
e9ec201450 | ||
|
|
93d48c7277 | ||
|
|
91488e88f5 | ||
|
|
fdae47c9b3 | ||
|
|
8b3abae5f5 | ||
|
|
0b87af884e | ||
|
|
3040dfc66e | ||
|
|
caf81f9f06 | ||
|
|
f8bde78717 | ||
|
|
a86046949a | ||
|
|
64d8b75f3e | ||
|
|
f1a56b9f91 | ||
|
|
645fd818d4 | ||
|
|
19b4026a50 | ||
|
|
81bf6d6ed9 | ||
|
|
50cac67efe | ||
|
|
a2d600a27e | ||
|
|
cb3ae9363d | ||
|
|
e602896dae | ||
|
|
beef2fd55b | ||
|
|
23bcc6924f | ||
|
|
2b5130a972 | ||
|
|
c23e57939e | ||
|
|
949f7c4936 | ||
|
|
55b0708016 | ||
|
|
376db85cf7 | ||
|
|
118469caa2 | ||
|
|
2391cf2cfe | ||
|
|
9934d87ffb | ||
|
|
af050c52d3 | ||
|
|
2bd41a9552 | ||
|
|
171a163531 | ||
|
|
0caa823ad6 | ||
|
|
7a39f24182 | ||
|
|
760e1b8ec8 | ||
|
|
772ad1a884 | ||
|
|
da9413930e | ||
|
|
74cd71e255 | ||
|
|
390f3e73d9 | ||
|
|
9436d8b1c8 | ||
|
|
39f2b22d69 | ||
|
|
e0de8bde94 | ||
|
|
f5fdaf32e6 | ||
|
|
e54858620b | ||
|
|
ece900b353 | ||
|
|
3e3773aab5 | ||
|
|
774f26066b | ||
|
|
c56fff2e78 | ||
|
|
c524f5bbfd | ||
|
|
fa4f0ae240 | ||
|
|
fd401108ee | ||
|
|
52af3fed5d | ||
|
|
52005fd480 | ||
|
|
d618a67826 | ||
|
|
1d9bcd1dba | ||
|
|
22c5324532 | ||
|
|
7b808bb821 | ||
|
|
551034179a | ||
|
|
4d6ab9ad4b | ||
|
|
ab6457d95c | ||
|
|
46d5cef377 | ||
|
|
f3e347c1cd | ||
|
|
a5d590b7ab | ||
|
|
1393206d07 | ||
|
|
c3cc83dd1c | ||
|
|
fdb93bbd96 | ||
|
|
ffb4721afd | ||
|
|
9559f0986e | ||
|
|
c8f4ceff9c | ||
|
|
63b20d1388 | ||
|
|
3f560d81a0 | ||
|
|
f8b92dc0b9 | ||
|
|
815f4d5999 | ||
|
|
59515a314e | ||
|
|
4ff12abc79 | ||
|
|
32cfc7676e | ||
|
|
d5ecbaadac | ||
|
|
872f46798a | ||
|
|
a9eda0a981 | ||
|
|
0dcaace2aa | ||
|
|
c5a2b2563b | ||
|
|
5636a91028 | ||
|
|
a9df5402e5 | ||
|
|
cb6323288e | ||
|
|
de7fbef45d | ||
|
|
e3133f28d4 | ||
|
|
ad0f40e638 | ||
|
|
3d8cbf3e72 | ||
|
|
2bf4c596d8 | ||
|
|
2b4534f403 | ||
|
|
7b273166ed | ||
|
|
ca37615bef | ||
|
|
34fdf7c5ce | ||
|
|
75d0e73836 | ||
|
|
f9b1a9e909 | ||
|
|
b589a5ff46 | ||
|
|
9ae1e5220f | ||
|
|
f1ace2f821 | ||
|
|
5246e6e83b | ||
|
|
1cab054da7 | ||
|
|
e2b3d7cdc6 | ||
|
|
a9a75b9280 | ||
|
|
585f937b81 | ||
|
|
029331aeb5 | ||
|
|
b612957863 | ||
|
|
6e79bc92f9 | ||
|
|
5b08275dfe | ||
|
|
4030166454 | ||
|
|
025d7f0c50 | ||
|
|
1922c24a7c | ||
|
|
66bd055455 | ||
|
|
bded1098bb | ||
|
|
4a3faa9761 | ||
|
|
e471f4a03f | ||
|
|
07dd11d97a | ||
|
|
f4b52d3a67 | ||
|
|
b71b56962d | ||
|
|
3a2a27f5cc |
2
.env.defaults
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
MASQR_ENABLED=false
|
||||||
|
PORT=3000
|
||||||
3
.eslintignore
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
public/
|
||||||
47
.eslintrc.cjs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
es2022: true,
|
||||||
|
browser: true,
|
||||||
|
},
|
||||||
|
extends: ["eslint:recommended", "plugin:astro/recommended"],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: "latest",
|
||||||
|
sourceType: "module",
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
"no-unused-vars": "error",
|
||||||
|
"no-undef": "off",
|
||||||
|
"prefer-const": "error",
|
||||||
|
"no-case-declarations": "off",
|
||||||
|
},
|
||||||
|
ignorePatterns: ["env.d.ts", "middleware/", "public/"],
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ["*.astro"],
|
||||||
|
parser: "astro-eslint-parser",
|
||||||
|
parserOptions: {
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
extraFileExtensions: [".astro"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ["*.ts", "*.tsx"],
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
parserOptions: {
|
||||||
|
project: "./tsconfig.json",
|
||||||
|
},
|
||||||
|
plugins: ["@typescript-eslint"],
|
||||||
|
extends: ["plugin:@typescript-eslint/recommended"],
|
||||||
|
rules: {
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Define the configuration for `<script>` tag.
|
||||||
|
// Script in `<script>` is assigned a virtual file name with the `.js` extension.
|
||||||
|
files: ["**/*.astro/*.js", "*.astro/*.js"],
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
1
.gitignore
vendored
|
|
@ -5,3 +5,4 @@ node_modules/
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
.env
|
.env
|
||||||
public/games/**
|
public/games/**
|
||||||
|
exempt_masqr.txt
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
dist
|
dist
|
||||||
node_modules
|
node_modules
|
||||||
|
public
|
||||||
4
.vscode/extensions.json
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"recommendations": ["astro-build.astro-vscode"],
|
|
||||||
"unwantedRecommendations": []
|
|
||||||
}
|
|
||||||
11
.vscode/launch.json
vendored
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"command": "./node_modules/.bin/astro dev",
|
|
||||||
"name": "Development server",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "node-terminal"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
11
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"search.exclude": {
|
||||||
|
"/public/games/**": true
|
||||||
|
},
|
||||||
|
"files.exclude": {
|
||||||
|
"**/*.rpyc": true,
|
||||||
|
"**/*.rpa": true,
|
||||||
|
"**/*.rpymc": true,
|
||||||
|
"**/cache/": true
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Checkfailed.html
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Welcome to nginx!</title>
|
||||||
|
<style>
|
||||||
|
html {
|
||||||
|
color-scheme: light dark;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
width: 35em;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-family: Tahoma, Verdana, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Welcome to nginx!</h1>
|
||||||
|
<p>
|
||||||
|
If you see this page, the nginx web server is successfully installed and working. Further configuration is required. If you are expecting another page, please check your network or
|
||||||
|
<a href="/" id="rcheck"><b>Refresh this page</b></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For online documentation and support please refer to
|
||||||
|
<a href="http://nginx.org/">nginx.org</a>.<br />
|
||||||
|
Commercial support is available at
|
||||||
|
<a href="http://nginx.com/">nginx.com</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><em>Thank you for using nginx.</em></p>
|
||||||
|
<script>
|
||||||
|
if (!localStorage["auth"] && new URL(document.all.rcheck.href).password) {
|
||||||
|
window.location.reload();
|
||||||
|
localStorage["auth"] = 1;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
Dockerfile
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
FROM node:lts
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# Copying package.json and pnpm-lock helps with caching
|
||||||
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
|
||||||
|
RUN npm i -g pnpm
|
||||||
|
|
||||||
|
RUN pnpm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN pnpm run build
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["pnpm", "start"]
|
||||||
37
README.md
|
|
@ -1,39 +1,58 @@
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://github.com/titaniumnetwork-dev/Alu/assets/99224452/d740378b-3fba-4470-8f06-3eefdae8a313" alt="AluLogo" width="250"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
# Alu
|
# Alu
|
||||||
|
|
||||||
Alu is a beautiful, functional, and sleek web proxy, which focuses on customization and ease of use.
|
Alu is a beautiful, functional, and sleek web proxy that prioritizes customization and ease of use.
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
- 🌐 UV and Rammerhead support
|
- 🌐 UV and Rammerhead support
|
||||||
- 🎨 Themes
|
- 🎨 Multiple Themes to choose from
|
||||||
|
- 🏬 Marketplace for Themes and Extensions
|
||||||
- 🕶 Multiple site cloaking options
|
- 🕶 Multiple site cloaking options
|
||||||
- 🎮 50+ Games to choose from
|
- 🎮 50+ Games to choose from
|
||||||
- 🌎 English and Japanese support
|
- 🌎 Support for **6** Languages
|
||||||
- 🚀 High performance
|
- 🚀 High performance
|
||||||
- 🔍 Multiple Search Engines to pick from
|
- 🔍 Multiple Search Engines to pick from
|
||||||
|
|
||||||
# Deploying Alu
|
# Deploying Alu
|
||||||
Deploying Alu is about as simple as it gets, from your terminal, type
|
|
||||||
|
|
||||||
`git clone https://github.com/wearrrrr/Alu --recursive-submodules`
|
Deploying Alu is about as simple as it gets.
|
||||||
|
|
||||||
This command should clone Alu's frontend, as well as [alu-games](https://github.com/wearrrrr/alu-games). If you wish to skip cloning games, then leave out the last flag.
|
1. Open your terminal and type `git clone https://github.com/titaniumnetwork-dev/Alu --recurse-submodules`
|
||||||
|
|
||||||
Then simply run `npm i` to install all node_modules, and then build the frontend with `npm run build`, this shouldn't take more than a couple seconds.
|
2. Install pnpm with `npm i -g pnpm`.
|
||||||
|
|
||||||
Finally, run `npm start` to actually serve Alu! It defaults to port 3000 for everything, but this can be specified in an env file.
|
3. Then simply run `pnpm i` to install all node_modules, and build the frontend with `pnpm run build`; this shouldn't take more than a couple seconds.
|
||||||
|
|
||||||
Congrats, you've now deployed your very own web proxy!
|
4. Finally, run `pnpm start` to actually serve Alu! It defaults to port 3000 for everything, but this can be specified in an env file.
|
||||||
|
|
||||||
|
Congrats! You should now be running your very own instance of Alu! 🎉
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Recursing all submodules will install [alu-games](https://github.com/wearrrrr/alu-games) as well. This repo contains _all_ games for Alu and is quite large! If you wish to skip it, simply remove `--recurse-submodules` from your clone command.
|
||||||
|
|
||||||
|
## What about Docker?
|
||||||
|
|
||||||
|
Alu can be easily dockerized with the `Dockerfile` provided in the repository. Simply run `docker build -t alu .` to build the image, and then `docker run -p 3000:3000 alu` to run the container, and you're good to go!
|
||||||
|
|
||||||
# Technologies
|
# Technologies
|
||||||
|
|
||||||
- Ultraviolet by Titanium Network
|
- Ultraviolet by Titanium Network
|
||||||
- Bare Server from TompHTTP
|
- Bare Server from TompHTTP
|
||||||
|
- Wisp Server Node by Mercury Workshop
|
||||||
- Rammerhead by binary-person
|
- Rammerhead by binary-person
|
||||||
- Astro from astro.build
|
- Astro from astro.build
|
||||||
- Typescript
|
- Typescript
|
||||||
- ExpressJS
|
- ExpressJS
|
||||||
- Prettier
|
- Prettier
|
||||||
|
- ESLint
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,31 @@
|
||||||
import { defineConfig } from "astro/config";
|
import { defineConfig } from "astro/config";
|
||||||
|
|
||||||
import node from "@astrojs/node";
|
import node from "@astrojs/node";
|
||||||
|
import dotenv from "dotenv-flow";
|
||||||
|
import sitemap from '@astrojs/sitemap';
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
// Check if node is running in production mode
|
||||||
|
// const prodBuild = process.env.NODE_ENV === "production";
|
||||||
|
const prodBuild = process.env.IS_PROD === "true";
|
||||||
|
|
||||||
|
const site = prodBuild ? "https://aluu.xyz" : "http://localhost:3000";
|
||||||
|
|
||||||
// https://astro.build/config
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [],
|
site: site,
|
||||||
output: "hybrid",
|
integrations: [
|
||||||
|
sitemap({
|
||||||
|
lastmod: new Date(),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
output: "server",
|
||||||
adapter: node({
|
adapter: node({
|
||||||
mode: "middleware",
|
mode: "middleware",
|
||||||
}),
|
}),
|
||||||
|
vite: {
|
||||||
|
server: {
|
||||||
|
watch: {
|
||||||
|
usePolling: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
184
index.js
|
|
@ -1,97 +1,139 @@
|
||||||
import { uvPath } from "@nebula-services/ultraviolet";
|
import "./middleware/catchErrors.js";
|
||||||
import { createBareServer } from "@tomphttp/bare-server-node";
|
import dotenv from "dotenv-flow";
|
||||||
|
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
|
||||||
|
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
|
||||||
|
import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
|
||||||
|
import { bareModulePath } from "@mercuryworkshop/bare-as-module3";
|
||||||
|
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { createServer } from "http";
|
import { createServer } from "http";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import createRammerhead from "rammerhead/src/server/index.js";
|
|
||||||
import compression from "compression";
|
|
||||||
import { build } from "astro";
|
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { existsSync } from "fs";
|
import { server as wisp, logging as wispLogging } from "@mercuryworkshop/wisp-js/server";
|
||||||
import dotenv from "dotenv";
|
import { handler as astroSSR } from "./dist/server/entry.mjs";
|
||||||
|
import cookies from "cookie-parser";
|
||||||
|
import { existsSync, readFileSync } from "fs";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
if (!existsSync("./dist")) build();
|
const whiteListedDomains = ["aluu.xyz", "localhost"];
|
||||||
|
|
||||||
const PORT = process.env.PORT || 3000;
|
if (existsSync("exempt_masqr.txt")) {
|
||||||
|
const file = readFileSync("exempt_masqr.txt", "utf-8");
|
||||||
const bare = createBareServer("/bare/");
|
const exemptDomains = file.split("\n");
|
||||||
console.log(chalk.gray("Starting Bare..."));
|
exemptDomains.forEach((domain) => {
|
||||||
|
whiteListedDomains.push(domain.trim());
|
||||||
const rh = createRammerhead();
|
});
|
||||||
console.log(chalk.gray("Starting Rammerhead..."));
|
|
||||||
|
|
||||||
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) {
|
const LICENSE_SERVER_URL = "https://license.mercurywork.shop/validate?license=";
|
||||||
rh.emit("request", req, res);
|
const MASQR_ENABLED = process.env.MASQR_ENABLED;
|
||||||
}
|
wispLogging.set_level(wispLogging.WARN);
|
||||||
|
|
||||||
function routeRhUpgrade(req, socket, head) {
|
const log = (message) => console.log(chalk.gray.bold("[Alu] " + message));
|
||||||
rh.emit("upgrade", req, socket, head);
|
const success = (message) => console.log(chalk.green.bold("[Alu] " + message));
|
||||||
}
|
|
||||||
|
|
||||||
let server = createServer();
|
|
||||||
server.on("request", (req, res) => {
|
|
||||||
if (bare.shouldRoute(req)) {
|
|
||||||
bare.routeRequest(req, res);
|
|
||||||
} else if (shouldRouteRh(req)) {
|
|
||||||
routeRhRequest(req, res);
|
|
||||||
} else {
|
|
||||||
app(req, res);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.on("upgrade", (req, socket, head) => {
|
|
||||||
if (bare.shouldRoute(req)) {
|
|
||||||
bare.routeUpgrade(req, socket, head);
|
|
||||||
} else if (shouldRouteRh(req)) {
|
|
||||||
routeRhUpgrade(req, socket, head);
|
|
||||||
} else {
|
|
||||||
socket.end();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const PORT = process.env.PORT;
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(compression());
|
|
||||||
|
app.use(cookies());
|
||||||
|
|
||||||
|
// Set process.env.MASQR_ENABLED to "true" to enable masqr protection.
|
||||||
|
if (MASQR_ENABLED == "true") {
|
||||||
|
log("Starting Masqr...");
|
||||||
|
const masqrCheck = (await import("./middleware/Masqr/index.js")).masqrCheck;
|
||||||
|
app.use(await masqrCheck({ whitelist: whiteListedDomains, licenseServer: LICENSE_SERVER_URL, htmlFile: "Checkfailed.html" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use(astroSSR);
|
||||||
|
|
||||||
app.use(express.static(path.join(process.cwd(), "static")));
|
app.use(express.static(path.join(process.cwd(), "static")));
|
||||||
app.use(express.static(path.join(process.cwd(), "build")));
|
app.use(express.static(path.join(process.cwd(), "build")));
|
||||||
app.use("/uv/", express.static(uvPath));
|
app.use("/uv/", express.static(uvPath));
|
||||||
|
app.use("/epoxy/", express.static(epoxyPath));
|
||||||
|
app.use("/libcurl/", express.static(libcurlPath));
|
||||||
|
app.use("/baremux/", express.static(baremuxPath));
|
||||||
|
app.use("/baremod/", express.static(bareModulePath));
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(
|
app.use(
|
||||||
express.urlencoded({
|
express.urlencoded({
|
||||||
extended: true,
|
extended: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
app.use("/", express.static("dist/client/"));
|
app.use((req, res, next) => {
|
||||||
|
if (req.url.includes("/games/")) {
|
||||||
|
res.header("Cross-Origin-Opener-Policy", "same-origin");
|
||||||
|
res.header("Cross-Origin-Embedder-Policy", "require-corp");
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
app.use("/custom-favicon", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { url } = req.query;
|
||||||
|
const response = await fetch(`https://www.google.com/s2/favicons?domain=${url}&sz=128`);
|
||||||
|
const buffer = new Buffer.from(await response.arrayBuffer());
|
||||||
|
res.set("Content-Type", "image/png");
|
||||||
|
res.send(buffer);
|
||||||
|
} catch {
|
||||||
|
res.sendStatus(500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
console.log(chalk.gray("Starting Alu..."));
|
app.use("/blocklist", async (req, res) => {
|
||||||
console.log(chalk.green("Alu started successfully!"));
|
try {
|
||||||
|
const { url } = req.query;
|
||||||
|
const response = await fetch(url).then((r) => r.text());
|
||||||
|
res.set("Content-Type", "text/plain");
|
||||||
|
res.send(response);
|
||||||
|
} catch {
|
||||||
|
res.sendStatus(500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use("/", express.static("dist/client/"));
|
||||||
|
app.get("/favicon.ico", (req, res) => {
|
||||||
|
res.sendFile(path.join(process.cwd(), "dist/client/favicon.svg"));
|
||||||
|
});
|
||||||
|
app.get("/robots.txt", (req, res) => {
|
||||||
|
if (req.headers.host && whiteListedDomains.includes(req.headers.host)) {
|
||||||
|
res.sendFile(path.join(process.cwd(), "dist/client/robots-allow.txt"));
|
||||||
|
} else {
|
||||||
|
res.sendFile(path.join(process.cwd(), "dist/client/robots-deny.txt"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.get("/search", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { query } = req.query;
|
||||||
|
|
||||||
|
const response = await fetch(`http://api.duckduckgo.com/ac?q=${query}&format=json`).then((apiRes) => apiRes.json());
|
||||||
|
|
||||||
|
res.send(response);
|
||||||
|
} catch (err) {
|
||||||
|
res.redirect(302, "/404.html");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.get("*", (req, res) => {
|
||||||
|
res.redirect(302, "/404");
|
||||||
|
});
|
||||||
|
|
||||||
|
const server = createServer();
|
||||||
|
server.on("request", (req, res) => {
|
||||||
|
app(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on("upgrade", (req, socket, head) => {
|
||||||
|
if (req.url.endsWith("/wisp/")) {
|
||||||
|
wisp.routeRequest(req, socket, head);
|
||||||
|
} else {
|
||||||
|
socket.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
log("Starting Alu...");
|
||||||
|
success("Alu started successfully!");
|
||||||
server.on("listening", () => {
|
server.on("listening", () => {
|
||||||
console.log(chalk.green(`Server running at http://localhost:${PORT}/.`));
|
success(`Server running at http://localhost:${PORT}/.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen({
|
server.listen({
|
||||||
|
|
|
||||||
73
middleware/Masqr/index.js
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
|
export async function masqrCheck(config) {
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const loadedHtmlFile = fs.readFileSync(process.cwd() + "/" + config.htmlFile, "utf8");
|
||||||
|
if (config.whitelist.includes(req.hostname)) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const authheader = req.headers.authorization;
|
||||||
|
|
||||||
|
if (!req.cookies) {
|
||||||
|
// Send an error
|
||||||
|
return res.send("Request failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.cookies.authcheck) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!authheader) {
|
||||||
|
res.setHeader("WWW-Authenticate", "Basic");
|
||||||
|
res.status(401);
|
||||||
|
MasqrFail(req, res, loadedHtmlFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If we are at this point, then the request should be a valid masqr request, and we are going to check the license server
|
||||||
|
const auth = Buffer.from(authheader.split(" ")[1], "base64").toString().split(":");
|
||||||
|
const pass = auth[1];
|
||||||
|
const licenseCheck = (await (await fetch(config.licenseServer + pass + "&host=" + req.headers.host)).json())["status"];
|
||||||
|
if (licenseCheck === "License valid") {
|
||||||
|
// Authenticated, set cookie for a year
|
||||||
|
res.cookie("authcheck", "true", {
|
||||||
|
expires: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
|
||||||
|
});
|
||||||
|
res.send(`<script>window.location.href = window.location.href</script>`); // fun hack to make the browser refresh and remove the auth params from the URL
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
res.setHeader("WWW-Authenticate", "Basic");
|
||||||
|
res.status(401);
|
||||||
|
MasqrFail(req, res, loadedHtmlFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500);
|
||||||
|
res.send("Internal server error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async function MasqrFail(req, res, failureFile) {
|
||||||
|
if (!req.headers.host) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const unsafeSuffix = req.headers.host + ".html";
|
||||||
|
const safeSuffix = path.normalize(unsafeSuffix).replace(/^(\.\.(\/|\\|$))+/, "");
|
||||||
|
const safeJoin = path.join(process.cwd() + "/Masqrd", safeSuffix);
|
||||||
|
try {
|
||||||
|
await fs.promises.access(safeJoin); // man do I wish this was an if-then instead of a "exception on fail"
|
||||||
|
const failureFileLocal = await fs.promises.readFile(safeJoin, "utf8");
|
||||||
|
res.setHeader("Content-Type", "text/html");
|
||||||
|
res.send(failureFileLocal);
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
res.setHeader("Content-Type", "text/html");
|
||||||
|
res.status(401);
|
||||||
|
res.send(failureFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
middleware/catchErrors.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
|
process.on("uncaughtException", (err) => {
|
||||||
|
console.log(chalk.bold.red(`[Alu] Caught error!\n${err.stack}`));
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("uncaughtExceptionMonitor", (err) => {
|
||||||
|
console.log(chalk.bold.red(`[Alu] Caught error!\n${err.stack}`));
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
9772
package-lock.json
generated
55
package.json
|
|
@ -1,36 +1,47 @@
|
||||||
{
|
{
|
||||||
"name": "alus-unblocker",
|
"name": "alu",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build:all": "npm run format && npm run lint && npm run build",
|
||||||
"start": "node .",
|
"start": "node .",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"lint": "prettier --write .",
|
"dev": "npm run build && npm run start",
|
||||||
"lint:check": "prettier --check ."
|
"format": "prettier --write .",
|
||||||
|
"format:check": "prettier --check .",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"lint:fix": "eslint --fix ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.4.0",
|
"@astrojs/node": "^9.0.0",
|
||||||
"@astrojs/node": "^7.0.4",
|
"@astrojs/sitemap": "^3.2.1",
|
||||||
"@nebula-services/ultraviolet": "^1.0.1-1.patch.5",
|
"@mercuryworkshop/bare-as-module3": "^2.2.5",
|
||||||
"@tomphttp/bare-server-node": "^2.0.1",
|
"@mercuryworkshop/bare-mux": "^2.1.5",
|
||||||
"astro": "^4.3.3",
|
"@mercuryworkshop/epoxy-transport": "^2.1.26",
|
||||||
"astro-i18n": "^2.2.4",
|
"@mercuryworkshop/libcurl-transport": "^1.3.14",
|
||||||
"astro-i18next": "^1.0.0-beta.21",
|
"@mercuryworkshop/wisp-js": "^0.3.3",
|
||||||
|
"@rubynetwork/rammerhead": "^1.3.5",
|
||||||
|
"@titaniumnetwork-dev/ultraviolet": "^3.2.10",
|
||||||
|
"@tomphttp/bare-server-node": "^2.0.5",
|
||||||
|
"@types/node": "^22.10.1",
|
||||||
|
"astro": "^5.0.1",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
"compression": "^1.7.4",
|
"cookie-parser": "^1.4.7",
|
||||||
"dotenv": "^16.3.1",
|
|
||||||
"dotenv-flow": "^4.1.0",
|
"dotenv-flow": "^4.1.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.21.1",
|
||||||
"i": "^0.3.7",
|
"notyf": "^3.10.0",
|
||||||
"i18next": "^23.7.18",
|
"sequelize": "^6.37.5",
|
||||||
"i18next-browser-languagedetector": "^7.2.0",
|
"sqlite3": "^5.1.7"
|
||||||
"npm": "^10.2.5",
|
|
||||||
"path": "^0.12.7",
|
|
||||||
"rammerhead": "https://github.com/holy-unblocker/rammerhead/releases/download/v1.2.41-holy.5/rammerhead-1.2.41-holy.5.tgz",
|
|
||||||
"typescript": "^5.3.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "3.2.5",
|
"@typescript-eslint/eslint-plugin": "^8.17.0",
|
||||||
"prettier-plugin-astro": "^0.13.0"
|
"@typescript-eslint/parser": "^8.17.0",
|
||||||
|
"eslint": "^9.16.0",
|
||||||
|
"eslint-plugin-astro": "^1.3.1",
|
||||||
|
"prettier": "3.4.1",
|
||||||
|
"prettier-plugin-astro": "^0.14.1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"bufferutil": "^4.0.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6360
pnpm-lock.yaml
generated
Normal file
|
|
@ -6,7 +6,7 @@ const config = {
|
||||||
bracketSameLine: true,
|
bracketSameLine: true,
|
||||||
arrowParens: "always",
|
arrowParens: "always",
|
||||||
plugins: ["prettier-plugin-astro"],
|
plugins: ["prettier-plugin-astro"],
|
||||||
printWidth: 100,
|
printWidth: 200,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 7.3 KiB |
37
public/favicon.svg
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 512 512" xml:space="preserve">
|
||||||
|
<path style="fill:#7067a1;" d="M494.176,64.787c15.4,22.42,20.974,52.758,16.123,88.421c-4.751,34.914-19.365,74.181-42.346,113.946
|
||||||
|
c52.234,90.354,58.519,172.178,16.073,214.624c-18.729,18.729-45.127,27.981-76.537,27.981c-39.777,0-87.598-14.839-138.087-44.017
|
||||||
|
c-50.489,29.178-98.309,44.017-138.087,44.017c-31.411,0-57.796-9.252-76.525-27.981c-42.458-42.434-36.186-124.245,16.036-214.611
|
||||||
|
c-10.287-17.806-18.904-35.525-25.724-52.858c-0.262,0-0.511,0.012-0.773,0.012C19.889,214.321,0,194.444,0,169.992
|
||||||
|
c0-18.23,11.073-33.917,26.834-40.713c-0.037-31.884,9.514-58.282,27.956-76.724C97.224,10.096,179.036,16.368,269.402,68.59
|
||||||
|
c52.92-30.575,104.057-45.912,145.818-43.83c7.619-13.43,22.046-22.52,38.568-22.52c24.44,0,44.329,19.889,44.329,44.329
|
||||||
|
C498.116,53.066,496.695,59.226,494.176,64.787z M485.585,149.854c3.591-26.41,0.611-48.755-8.616-65.514
|
||||||
|
c-6.758,4.152-14.689,6.559-23.181,6.559c-23.455,0-42.695-18.318-44.217-41.386c-33.119-0.561-73.32,11.272-115.891,34.104
|
||||||
|
c30.4,20.051,59.741,44.142,87.436,71.836c27.695,27.695,51.773,57.035,71.811,87.423
|
||||||
|
C470.509,210.044,481.732,178.197,485.585,149.854z M473.178,46.569c0-10.686-8.704-19.39-19.39-19.39
|
||||||
|
c-10.686,0-19.39,8.704-19.39,19.39s8.704,19.39,19.39,19.39S473.178,57.256,473.178,46.569z M466.394,464.146
|
||||||
|
c31.884-31.897,26.273-98.421-13.467-172.689c-20.038,30.388-44.117,59.729-71.811,87.423
|
||||||
|
c-27.695,27.695-57.023,51.773-87.423,71.824C367.961,490.431,434.497,496.043,466.394,464.146z M438.887,267.166
|
||||||
|
c-20.35-32.745-45.688-64.367-75.403-94.082c-29.715-29.702-61.325-55.053-94.082-75.415
|
||||||
|
c-32.757,20.363-64.367,45.713-94.082,75.415c-29.702,29.715-55.053,61.325-75.415,94.082
|
||||||
|
c20.363,32.757,45.713,64.367,75.415,94.082c29.715,29.702,61.325,55.053,94.082,75.415c32.757-20.363,64.367-45.713,94.082-75.415
|
||||||
|
C393.199,331.533,418.537,299.911,438.887,267.166z M157.688,155.452c27.682-27.695,57.023-51.773,87.423-71.824
|
||||||
|
C170.831,43.901,104.307,38.29,72.422,70.186c-13.093,13.105-20.138,32.358-20.637,56.125c20.899,3.554,36.872,21.784,36.872,43.68
|
||||||
|
c0,15.337-7.818,28.867-19.677,36.835c4.738,11.834,10.375,23.891,16.884,36.062C105.915,212.488,129.994,183.147,157.688,155.452z
|
||||||
|
M245.112,450.704c-30.4-20.051-59.729-44.129-87.423-71.824c-27.695-27.695-51.773-57.023-71.824-87.423
|
||||||
|
c-39.728,74.268-45.339,140.805-13.442,172.689C104.307,496.043,170.831,490.431,245.112,450.704z M63.719,169.992
|
||||||
|
c0-10.686-8.691-19.39-19.39-19.39c-10.686,0-19.39,8.704-19.39,19.39c0,10.699,8.704,19.39,19.39,19.39
|
||||||
|
C55.028,189.382,63.719,180.691,63.719,169.992z"/>
|
||||||
|
<path style="fill:#9e8feb;" d="M453.788,27.179c10.686,0,19.39,8.704,19.39,19.39s-8.704,19.39-19.39,19.39
|
||||||
|
c-10.686,0-19.39-8.704-19.39-19.39S443.101,27.179,453.788,27.179z"/>
|
||||||
|
<path style="fill:#7067a1;" d="M269.402,201.253c36.348,0,65.913,29.565,65.913,65.913c0,36.336-29.565,65.913-65.913,65.913
|
||||||
|
c-36.336,0-65.901-29.577-65.901-65.913C203.501,230.818,233.066,201.253,269.402,201.253z M310.377,267.166
|
||||||
|
c0-22.595-18.38-40.975-40.975-40.975c-22.582,0-40.962,18.38-40.962,40.975s18.38,40.975,40.962,40.975
|
||||||
|
C291.997,308.141,310.377,289.761,310.377,267.166z"/>
|
||||||
|
<path style="fill:#fbb0ff;" d="M269.402,226.192c22.595,0,40.975,18.38,40.975,40.975s-18.38,40.975-40.975,40.975
|
||||||
|
c-22.582,0-40.962-18.38-40.962-40.975S246.82,226.192,269.402,226.192z"/>
|
||||||
|
<path style="fill:#9e8feb;" d="M44.329,150.602c10.699,0,19.39,8.704,19.39,19.39c0,10.699-8.691,19.39-19.39,19.39
|
||||||
|
c-10.686,0-19.39-8.691-19.39-19.39C24.939,159.306,33.643,150.602,44.329,150.602z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
33
public/flash/instantiateFlash.js
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
const id = window.location.pathname.split("/").pop();
|
||||||
|
if (id && RufflePlayer) {
|
||||||
|
document.title = `Flash Game - ${id}`;
|
||||||
|
window.addEventListener("load", loadRuffle);
|
||||||
|
} else {
|
||||||
|
document.querySelector("#loader").classList.add("hidden");
|
||||||
|
document.querySelector("#error").classList.remove("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadRuffle() {
|
||||||
|
const ruffle = RufflePlayer.newest().createPlayer();
|
||||||
|
ruffle.config = {
|
||||||
|
splashScreen: false,
|
||||||
|
unmuteOverlay: "hidden",
|
||||||
|
autoplay: "on",
|
||||||
|
contextMenu: "on",
|
||||||
|
showSwfDownload: false
|
||||||
|
};
|
||||||
|
ruffle.style.width = "100%";
|
||||||
|
ruffle.style.height = "100%";
|
||||||
|
const gameContainer = document.querySelector("#gameContainer");
|
||||||
|
if (gameContainer != null) {
|
||||||
|
gameContainer.appendChild(ruffle);
|
||||||
|
}
|
||||||
|
ruffle.load(`/games/flash/${id}.swf`).then(() => {
|
||||||
|
let loader = document.querySelector("#loader");
|
||||||
|
loader.classList.remove("loading");
|
||||||
|
loader.classList.add("hidden");
|
||||||
|
document.querySelector("#gameContainer").classList.remove("hidden");
|
||||||
|
});
|
||||||
|
// Stop the event listener, saves miniscule amount of memory
|
||||||
|
window.removeEventListener("load", loadRuffle);
|
||||||
|
}
|
||||||
73
public/game.css
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
.vertical {
|
||||||
|
height: 70vh !important;
|
||||||
|
width: 30% !important;
|
||||||
|
aspect-ratio: auto !important;
|
||||||
|
}
|
||||||
|
#main-content {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
.game-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
background: var(--dropdown-background-color);
|
||||||
|
width: 80%;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 4rem;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
#game-frame {
|
||||||
|
aspect-ratio: 16 / 8;
|
||||||
|
height: 80vh;
|
||||||
|
width: 1350px;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flash-frame {
|
||||||
|
width: 1024px !important;
|
||||||
|
height: 576px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
background-color: var(--background-highlight);
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.game-info-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
.icn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.game-info-left {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
.game-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-img {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid var(--accent-color-brighter);
|
||||||
|
box-shadow: 0px 0px 20px 5px var(--accent-color-brighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-desc {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit beacfb38111fdfd430f75bc9684fca4e25f4dccc
|
Subproject commit 3b028f45966cc75fc1fd73e92d78f7eb0d7cfcba
|
||||||
BIN
public/icons/canvas.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
public/icons/classlink.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/icons/classroom.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
public/icons/clever.jpg
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
public/icons/drive.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/icons/edgenuity.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
public/icons/google.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
public/icons/schoology.webp
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
public/icons/youtube.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
11
public/iframe.css
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
/* CSS for about:blank iframes */
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<svg width="100%" height="100%" preserveAspectRatio="none" id="svg" viewBox="0 0 1440 390"
|
|
||||||
xmlns="http://www.w3.org/2000/svg" class="transition duration-300 ease-in-out delay-150">
|
|
||||||
<style>
|
|
||||||
.path-0{
|
|
||||||
animation:pathAnim-0 15s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
@keyframes pathAnim-0{
|
|
||||||
0%{
|
|
||||||
d: path("M 0,400 L 0,100 C 124.53333333333336,122.66666666666667 249.06666666666672,145.33333333333334 415,143 C 580.9333333333333,140.66666666666666 788.2666666666667,113.33333333333333 966,102 C 1143.7333333333333,90.66666666666667 1291.8666666666668,95.33333333333334 1440,100 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
d: path("M 0,400 L 0,100 C 171.19999999999993,71.6 342.39999999999986,43.2 497,54 C 651.6000000000001,64.8 789.6000000000001,114.80000000000001 944,129 C 1098.3999999999999,143.2 1269.1999999999998,121.6 1440,100 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
50%{
|
|
||||||
d: path("M 0,400 L 0,100 C 186.66666666666669,82.13333333333333 373.33333333333337,64.26666666666667 540,54 C 706.6666666666666,43.733333333333334 853.3333333333333,41.06666666666666 1000,50 C 1146.6666666666667,58.93333333333334 1293.3333333333335,79.46666666666667 1440,100 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
75%{
|
|
||||||
d: path("M 0,400 L 0,100 C 110.13333333333333,74.53333333333333 220.26666666666665,49.06666666666666 393,58 C 565.7333333333333,66.93333333333334 801.0666666666666,110.26666666666668 986,123 C 1170.9333333333334,135.73333333333332 1305.4666666666667,117.86666666666666 1440,100 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
d: path("M 0,400 L 0,100 C 124.53333333333336,122.66666666666667 249.06666666666672,145.33333333333334 415,143 C 580.9333333333333,140.66666666666666 788.2666666666667,113.33333333333333 966,102 C 1143.7333333333333,90.66666666666667 1291.8666666666668,95.33333333333334 1440,100 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
<style media="screen"></style>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="gradient" x1="0%" y1="53%" x2="100%" y2="47%">
|
|
||||||
<stop offset="5%" stop-color="#702dc2"></stop>
|
|
||||||
<stop offset="95%" stop-color="#3d097d"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d="M 0,400 L 0,100 C 124.53333333333336,122.66666666666667 249.06666666666672,145.33333333333334 415,143 C 580.9333333333333,140.66666666666666 788.2666666666667,113.33333333333333 966,102 C 1143.7333333333333,90.66666666666667 1291.8666666666668,95.33333333333334 1440,100 L 1440,400 L 0,400 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="0.53" class="transition-all duration-300 ease-in-out delay-150 path-0"></path>
|
|
||||||
<style>
|
|
||||||
.path-1{
|
|
||||||
animation:pathAnim-1 15s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
@keyframes pathAnim-1{
|
|
||||||
0%{
|
|
||||||
d: path("M 0,400 L 0,233 C 170.53333333333336,233.66666666666666 341.0666666666667,234.33333333333331 507,236 C 672.9333333333333,237.66666666666669 834.2666666666667,240.33333333333334 989,240 C 1143.7333333333333,239.66666666666666 1291.8666666666668,236.33333333333331 1440,233 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
d: path("M 0,400 L 0,233 C 202,220.46666666666667 404,207.93333333333334 539,220 C 674,232.06666666666666 742.0000000000001,268.7333333333333 881,275 C 1019.9999999999999,281.2666666666667 1230,257.1333333333333 1440,233 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
50%{
|
|
||||||
d: path("M 0,400 L 0,233 C 181.33333333333337,210.86666666666667 362.66666666666674,188.73333333333332 512,188 C 661.3333333333333,187.26666666666668 778.6666666666665,207.93333333333334 928,219 C 1077.3333333333335,230.06666666666666 1258.6666666666667,231.53333333333333 1440,233 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
75%{
|
|
||||||
d: path("M 0,400 L 0,233 C 195.06666666666666,222.86666666666667 390.1333333333333,212.73333333333332 559,216 C 727.8666666666667,219.26666666666668 870.5333333333333,235.93333333333334 1013,241 C 1155.4666666666667,246.06666666666666 1297.7333333333333,239.53333333333333 1440,233 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
d: path("M 0,400 L 0,233 C 170.53333333333336,233.66666666666666 341.0666666666667,234.33333333333331 507,236 C 672.9333333333333,237.66666666666669 834.2666666666667,240.33333333333334 989,240 C 1143.7333333333333,239.66666666666666 1291.8666666666668,236.33333333333331 1440,233 L 1440,400 L 0,400 Z");
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
<style media="screen"></style>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="gradient" x1="0%" y1="53%" x2="100%" y2="47%">
|
|
||||||
<stop offset="5%" stop-color="#702dc2"></stop>
|
|
||||||
<stop offset="95%" stop-color="#3d097d"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d="M 0,400 L 0,233 C 170.53333333333336,233.66666666666666 341.0666666666667,234.33333333333331 507,236 C 672.9333333333333,237.66666666666669 834.2666666666667,240.33333333333334 989,240 C 1143.7333333333333,239.66666666666666 1291.8666666666668,236.33333333333331 1440,233 L 1440,400 L 0,400 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="1" class="transition-all duration-300 ease-in-out delay-150 path-1"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 5.3 KiB |
3
public/img/checkmark.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-check" viewBox="0 0 16 16">
|
||||||
|
<path fill="#fff" d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 283 B |
4
public/img/games/fullscreen.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<svg stroke="#fff" fill="#fff" stroke-width="0" viewBox="0 0 256 256" height="1em" width="1em"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M220,48V88a12,12,0,0,1-24,0V60H168a12,12,0,0,1,0-24h40A12,12,0,0,1,220,48ZM88,196H60V168a12,12,0,0,0-24,0v40a12,12,0,0,0,12,12H88a12,12,0,0,0,0-24Zm120-40a12,12,0,0,0-12,12v28H168a12,12,0,0,0,0,24h40a12,12,0,0,0,12-12V168A12,12,0,0,0,208,156ZM88,36H48A12,12,0,0,0,36,48V88a12,12,0,0,0,24,0V60H88a12,12,0,0,0,0-24Z"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 477 B |
3
public/img/games/pin-outline.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<path fill="#fff" d="M21.436 7.586l-3.998-4.02c-.752-.756-2.063-.764-2.83-.006-.196.196-.35.436-.418.629-.653 1.362-1.354 2.215-2.254 2.727l-.217.105c-.968.485-2.285.979-4.719.979-.266 0-.521.052-.766.152-.484.202-.879.595-1.082 1.084-.199.484-.199 1.041 0 1.525.104.249.25.471.435.651l3.235 3.235-3.822 5.353 5.352-3.822 3.227 3.227c.186.189.406.339.656.441.247.103.503.154.766.154s.519-.052.765-.154c.498-.205.883-.592 1.08-1.078.103-.242.155-.507.155-.768 0-2.436.494-3.752.978-4.721.496-.992 1.369-1.748 2.754-2.414.271-.104.51-.256.711-.457.772-.782.768-2.051-.008-2.822zm-5.248 4.801c-.819 1.643-1.188 3.37-1.195 5.604l-7.993-7.991c2.139 0 3.814-.335 5.396-1.084l.235-.105c1.399-.699 2.468-1.893 3.388-3.834l3.924 4.051c-1.863.893-3.056 1.96-3.755 3.359z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 892 B |
3
public/img/games/pin.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<path fill="#fff" d="M16.729 4.271c-.389-.391-1.021-.393-1.414-.004-.104.104-.176.227-.225.355-.832 1.736-1.748 2.715-2.904 3.293-1.297.64-2.786 1.085-5.186 1.085-.13 0-.26.025-.382.076-.245.102-.439.297-.541.541-.101.244-.101.52 0 .764.051.123.124.234.217.326l3.243 3.243-4.537 6.05 6.05-4.537 3.242 3.242c.092.094.203.166.326.217.122.051.252.078.382.078s.26-.027.382-.078c.245-.102.44-.295.541-.541.051-.121.077-.252.077-.381 0-2.4.444-3.889 1.083-5.166.577-1.156 1.556-2.072 3.293-2.904.129-.049.251-.121.354-.225.389-.393.387-1.025-.004-1.414l-3.997-4.02z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 691 B |
|
|
@ -1,96 +0,0 @@
|
||||||
<svg width="100%" height="100%" id="svg" viewBox="0 0 1440 590"
|
|
||||||
xmlns="http://www.w3.org/2000/svg" class="transition duration-300 ease-in-out delay-150">
|
|
||||||
<style>
|
|
||||||
.path-0{
|
|
||||||
animation:pathAnim-0 15s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
@keyframes pathAnim-0{
|
|
||||||
0%{
|
|
||||||
d: path("M 0,600 L 0,112 C 283.5,125.5 567,139 807,139 C 1047,139 1243.5,125.5 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
d: path("M 0,600 L 0,112 C 289.5,106 579,100 819,100 C 1059,100 1249.5,106 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
50%{
|
|
||||||
d: path("M 0,600 L 0,112 C 300.5,84 601,56 841,56 C 1081,56 1260.5,84 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
75%{
|
|
||||||
d: path("M 0,600 L 0,112 C 256,112.5 512,113 752,113 C 992,113 1216,112.5 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
d: path("M 0,600 L 0,112 C 283.5,125.5 567,139 807,139 C 1047,139 1243.5,125.5 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
<style media="screen"></style>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%">
|
|
||||||
<stop offset="5%" stop-color="#1e2030"></stop>
|
|
||||||
<stop offset="95%" stop-color="#181926"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d="M 0,600 L 0,112 C 283.5,125.5 567,139 807,139 C 1047,139 1243.5,125.5 1440,112 L 1440,600 L 0,600 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="0.4" class="transition-all duration-300 ease-in-out delay-150 path-0"></path>
|
|
||||||
<style>
|
|
||||||
.path-1{
|
|
||||||
animation:pathAnim-1 15s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
@keyframes pathAnim-1{
|
|
||||||
0%{
|
|
||||||
d: path("M 0,600 L 0,262 C 259,246.5 518,231 758,231 C 998,231 1219,246.5 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
d: path("M 0,600 L 0,262 C 191,240.5 382,219 622,219 C 862,219 1151,240.5 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
50%{
|
|
||||||
d: path("M 0,600 L 0,262 C 305.5,268.5 611,275 851,275 C 1091,275 1265.5,268.5 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
75%{
|
|
||||||
d: path("M 0,600 L 0,262 C 286,273.5 572,285 812,285 C 1052,285 1246,273.5 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
d: path("M 0,600 L 0,262 C 259,246.5 518,231 758,231 C 998,231 1219,246.5 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
<style media="screen"></style>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%">
|
|
||||||
<stop offset="5%" stop-color="#1e2030"></stop>
|
|
||||||
<stop offset="95%" stop-color="#181926"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d="M 0,600 L 0,262 C 259,246.5 518,231 758,231 C 998,231 1219,246.5 1440,262 L 1440,600 L 0,600 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="0.53" class="transition-all duration-300 ease-in-out delay-150 path-1"></path>
|
|
||||||
<style>
|
|
||||||
.path-2{
|
|
||||||
animation:pathAnim-2 15s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
@keyframes pathAnim-2{
|
|
||||||
0%{
|
|
||||||
d: path("M 0,600 L 0,412 C 209,406.5 418,401 658,401 C 898,401 1169,406.5 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
d: path("M 0,600 L 0,412 C 218,423 436,434 676,434 C 916,434 1178,423 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
50%{
|
|
||||||
d: path("M 0,600 L 0,412 C 264,431 528,450 768,450 C 1008,450 1224,431 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
75%{
|
|
||||||
d: path("M 0,600 L 0,412 C 245.5,439.5 491,467 731,467 C 971,467 1205.5,439.5 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
d: path("M 0,600 L 0,412 C 209,406.5 418,401 658,401 C 898,401 1169,406.5 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
<style media="screen"></style>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%">
|
|
||||||
<stop offset="5%" stop-color="#1e2030"></stop>
|
|
||||||
<stop offset="95%" stop-color="#181926"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d="M 0,600 L 0,412 C 209,406.5 418,401 658,401 C 898,401 1169,406.5 1440,412 L 1440,600 L 0,600 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="1" class="transition-all duration-300 ease-in-out delay-150 path-2"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.5 KiB |
|
|
@ -1,93 +0,0 @@
|
||||||
<svg width="100%" height="100%" id="svg" viewBox="0 0 1440 590"
|
|
||||||
xmlns="http://www.w3.org/2000/svg" class="transition duration-300 ease-in-out delay-150">
|
|
||||||
<style>
|
|
||||||
.path-0{
|
|
||||||
animation:pathAnim-0 15s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
@keyframes pathAnim-0{
|
|
||||||
0%{
|
|
||||||
d: path("M 0,600 L 0,112 C 133.2,136.13333333333333 266.4,160.26666666666668 417,163 C 567.6,165.73333333333332 735.5999999999999,147.06666666666666 909,135 C 1082.4,122.93333333333334 1261.2,117.46666666666667 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
d: path("M 0,600 L 0,112 C 166.53333333333336,123.60000000000001 333.0666666666667,135.20000000000002 475,129 C 616.9333333333333,122.79999999999998 734.2666666666667,98.79999999999998 891,93 C 1047.7333333333333,87.20000000000002 1243.8666666666668,99.60000000000001 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
50%{
|
|
||||||
d: path("M 0,600 L 0,112 C 178.66666666666669,132.53333333333333 357.33333333333337,153.06666666666666 507,164 C 656.6666666666666,174.93333333333334 777.3333333333333,176.26666666666668 928,166 C 1078.6666666666667,155.73333333333332 1259.3333333333335,133.86666666666667 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
75%{
|
|
||||||
d: path("M 0,600 L 0,112 C 152,116.4 304,120.8 482,107 C 660,93.2 864,61.199999999999996 1028,59 C 1192,56.800000000000004 1316,84.4 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
d: path("M 0,600 L 0,112 C 133.2,136.13333333333333 266.4,160.26666666666668 417,163 C 567.6,165.73333333333332 735.5999999999999,147.06666666666666 909,135 C 1082.4,122.93333333333334 1261.2,117.46666666666667 1440,112 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%">
|
|
||||||
<stop offset="5%" stop-color="#181825"></stop>
|
|
||||||
<stop offset="95%" stop-color="#11111b"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d="M 0,600 L 0,112 C 133.2,136.13333333333333 266.4,160.26666666666668 417,163 C 567.6,165.73333333333332 735.5999999999999,147.06666666666666 909,135 C 1082.4,122.93333333333334 1261.2,117.46666666666667 1440,112 L 1440,600 L 0,600 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="0.4" class="transition-all duration-300 ease-in-out delay-150 path-0"></path>
|
|
||||||
<style>
|
|
||||||
.path-1{
|
|
||||||
animation:pathAnim-1 15s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
@keyframes pathAnim-1{
|
|
||||||
0%{
|
|
||||||
d: path("M 0,600 L 0,262 C 126.53333333333336,275.4666666666667 253.06666666666672,288.93333333333334 423,294 C 592.9333333333333,299.06666666666666 806.2666666666667,295.73333333333335 983,289 C 1159.7333333333333,282.26666666666665 1299.8666666666668,272.1333333333333 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
d: path("M 0,600 L 0,262 C 111.46666666666664,236.13333333333333 222.93333333333328,210.26666666666668 393,211 C 563.0666666666667,211.73333333333332 791.7333333333333,239.06666666666666 976,252 C 1160.2666666666667,264.93333333333334 1300.1333333333332,263.4666666666667 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
50%{
|
|
||||||
d: path("M 0,600 L 0,262 C 164.66666666666663,293.3333333333333 329.33333333333326,324.66666666666663 508,314 C 686.6666666666667,303.33333333333337 879.3333333333335,250.66666666666669 1037,235 C 1194.6666666666665,219.33333333333331 1317.3333333333333,240.66666666666666 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
75%{
|
|
||||||
d: path("M 0,600 L 0,262 C 122.13333333333333,279.4666666666667 244.26666666666665,296.93333333333334 392,303 C 539.7333333333333,309.06666666666666 713.0666666666668,303.73333333333335 892,295 C 1070.9333333333332,286.26666666666665 1255.4666666666667,274.1333333333333 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
d: path("M 0,600 L 0,262 C 126.53333333333336,275.4666666666667 253.06666666666672,288.93333333333334 423,294 C 592.9333333333333,299.06666666666666 806.2666666666667,295.73333333333335 983,289 C 1159.7333333333333,282.26666666666665 1299.8666666666668,272.1333333333333 1440,262 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%">
|
|
||||||
<stop offset="5%" stop-color="#181825"></stop>
|
|
||||||
<stop offset="95%" stop-color="#11111b"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d="M 0,600 L 0,262 C 126.53333333333336,275.4666666666667 253.06666666666672,288.93333333333334 423,294 C 592.9333333333333,299.06666666666666 806.2666666666667,295.73333333333335 983,289 C 1159.7333333333333,282.26666666666665 1299.8666666666668,272.1333333333333 1440,262 L 1440,600 L 0,600 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="0.53" class="transition-all duration-300 ease-in-out delay-150 path-1"></path>
|
|
||||||
<style>
|
|
||||||
.path-2{
|
|
||||||
animation:pathAnim-2 15s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
@keyframes pathAnim-2{
|
|
||||||
0%{
|
|
||||||
d: path("M 0,600 L 0,412 C 126,431.20000000000005 252,450.40000000000003 417,459 C 582,467.59999999999997 786,465.6 963,456 C 1140,446.4 1290,429.2 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
25%{
|
|
||||||
d: path("M 0,600 L 0,412 C 186.93333333333334,388 373.8666666666667,364 512,368 C 650.1333333333333,372 739.4666666666667,404 886,416 C 1032.5333333333333,428 1236.2666666666667,420 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
50%{
|
|
||||||
d: path("M 0,600 L 0,412 C 139.33333333333331,406.4 278.66666666666663,400.8 438,405 C 597.3333333333334,409.2 776.6666666666667,423.20000000000005 947,426 C 1117.3333333333333,428.79999999999995 1278.6666666666665,420.4 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
75%{
|
|
||||||
d: path("M 0,600 L 0,412 C 168.66666666666663,412.1333333333333 337.33333333333326,412.2666666666667 491,413 C 644.6666666666667,413.7333333333333 783.3333333333335,415.06666666666666 939,415 C 1094.6666666666665,414.93333333333334 1267.3333333333333,413.4666666666667 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
d: path("M 0,600 L 0,412 C 126,431.20000000000005 252,450.40000000000003 417,459 C 582,467.59999999999997 786,465.6 963,456 C 1140,446.4 1290,429.2 1440,412 L 1440,600 L 0,600 Z");
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%">
|
|
||||||
<stop offset="5%" stop-color="#181825"></stop>
|
|
||||||
<stop offset="95%" stop-color="#11111b"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<path d="M 0,600 L 0,412 C 126,431.20000000000005 252,450.40000000000003 417,459 C 582,467.59999999999997 786,465.6 963,456 C 1140,446.4 1290,429.2 1440,412 L 1440,600 L 0,600 Z" stroke="none" stroke-width="0" fill="url(#gradient)" fill-opacity="1" class="transition-all duration-300 ease-in-out delay-150 path-2"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 7.2 KiB |
5
public/img/nav/backwards.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#fff" fill-rule="evenodd" clip-rule="evenodd" d="M11.7071 4.29289C12.0976 4.68342 12.0976 5.31658 11.7071 5.70711L6.41421 11H20C20.5523 11 21 11.4477 21 12C21 12.5523 20.5523 13 20 13H6.41421L11.7071 18.2929C12.0976 18.6834 12.0976 19.3166 11.7071 19.7071C11.3166 20.0976 10.6834 20.0976 10.2929 19.7071L3.29289 12.7071C3.10536 12.5196 3 12.2652 3 12C3 11.7348 3.10536 11.4804 3.29289 11.2929L10.2929 4.29289C10.6834 3.90237 11.3166 3.90237 11.7071 4.29289Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 616 B |
3
public/img/nav/close.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
|
||||||
|
<path fill="#fc847c" d="M376.6 84.5c11.3-13.6 9.5-33.8-4.1-45.1s-33.8-9.5-45.1 4.1L192 206 56.6 43.5C45.3 29.9 25.1 28.1 11.5 39.4S-3.9 70.9 7.4 84.5L150.3 256 7.4 427.5c-11.3 13.6-9.5 33.8 4.1 45.1s33.8 9.5 45.1-4.1L192 306 327.4 468.5c11.3 13.6 31.5 15.4 45.1 4.1s15.4-31.5 4.1-45.1L233.7 256 376.6 84.5z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 384 B |
5
public/img/nav/forwards.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#fff" fill-rule="evenodd" clip-rule="evenodd" d="M12.2929 4.29289C12.6834 3.90237 13.3166 3.90237 13.7071 4.29289L20.7071 11.2929C21.0976 11.6834 21.0976 12.3166 20.7071 12.7071L13.7071 19.7071C13.3166 20.0976 12.6834 20.0976 12.2929 19.7071C11.9024 19.3166 11.9024 18.6834 12.2929 18.2929L17.5858 13H4C3.44772 13 3 12.5523 3 12C3 11.4477 3.44772 11 4 11H17.5858L12.2929 5.70711C11.9024 5.31658 11.9024 4.68342 12.2929 4.29289Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 587 B |
3
public/img/nav/reload.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<path fill="#fff" d="M463.5 224l8.5 0c13.3 0 24-10.7 24-24l0-128c0-9.7-5.8-18.5-14.8-22.2s-19.3-1.7-26.2 5.2L413.4 96.6c-87.6-86.5-228.7-86.2-315.8 1c-87.5 87.5-87.5 229.3 0 316.8s229.3 87.5 316.8 0c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0c-62.5 62.5-163.8 62.5-226.3 0s-62.5-163.8 0-226.3c62.2-62.2 162.7-62.5 225.3-1L327 183c-6.9 6.9-8.9 17.2-5.2 26.2s12.5 14.8 22.2 14.8l119.5 0z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 464 B |
15
public/img/nav/share.svg
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#fff" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 458.624 458.624" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M339.588,314.529c-14.215,0-27.456,4.133-38.621,11.239l-112.682-78.67c1.809-6.315,2.798-12.976,2.798-19.871
|
||||||
|
c0-6.896-0.989-13.557-2.798-19.871l109.64-76.547c11.764,8.356,26.133,13.286,41.662,13.286c39.79,0,72.047-32.257,72.047-72.047
|
||||||
|
C411.634,32.258,379.378,0,339.588,0c-39.79,0-72.047,32.257-72.047,72.047c0,5.255,0.578,10.373,1.646,15.308l-112.424,78.491
|
||||||
|
c-10.974-6.759-23.892-10.666-37.727-10.666c-39.79,0-72.047,32.257-72.047,72.047s32.256,72.047,72.047,72.047
|
||||||
|
c13.834,0,26.753-3.907,37.727-10.666l113.292,79.097c-1.629,6.017-2.514,12.34-2.514,18.872c0,39.79,32.257,72.047,72.047,72.047
|
||||||
|
c39.79,0,72.047-32.257,72.047-72.047C411.635,346.787,379.378,314.529,339.588,314.529z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"nav": {
|
|
||||||
"brand": "Alu",
|
|
||||||
"games": "Games",
|
|
||||||
"settings": "Settings"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"brand": "アルー",
|
|
||||||
"games": "ゲーム",
|
|
||||||
"settings": "設定"
|
|
||||||
}
|
|
||||||
BIN
public/marketplace/adblock/banner.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
public/marketplace/adblock/icon.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
166
public/marketplace/adblock/index.js
Normal file
BIN
public/marketplace/atom-one-dark/logo.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
9
public/marketplace/atom-one-dark/theme.css
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[data-theme="atom-one-dark"] {
|
||||||
|
--background-color: #1e2127;
|
||||||
|
--background-highlight: #434952;
|
||||||
|
--accent-color: #3a3f4b;
|
||||||
|
--accent-color-brighter: #4b515f;
|
||||||
|
--text-color: #abb2bf;
|
||||||
|
--text-color-accent: #989eaa;
|
||||||
|
--dropdown-background-color: #30353f;
|
||||||
|
}
|
||||||
56
public/marketplace/dracula-theme/logo.svg
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
<svg width="190" height="190" viewBox="0 0 190 190" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_511_171)">
|
||||||
|
<circle cx="95" cy="95" r="75" fill="white" fill-opacity="0.18" shape-rendering="crispEdges"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#clip0_511_171)">
|
||||||
|
<path d="M95 165C133.66 165 165 133.66 165 95C165 56.3401 133.66 25 95 25C56.3401 25 25 56.3401 25 95C25 133.66 56.3401 165 95 165Z" fill="black" fill-opacity="0.24"/>
|
||||||
|
<path d="M153.503 83.6581C153.503 100.319 146.557 115.357 135.403 126.035C131.708 129.574 127.55 132.631 123.03 135.111C114.667 139.703 105.059 142.315 94.8455 142.315C84.6318 142.315 75.0289 139.706 66.6659 135.114C65.3178 134.376 64.0037 133.586 62.7251 132.746C59.7085 130.771 56.8855 128.52 54.2904 126.035C43.1357 115.359 36.1877 100.319 36.1877 83.6578C36.1877 51.262 62.4497 25 94.8455 25C127.241 25 153.503 51.2623 153.503 83.6581Z" fill="white" fill-opacity="0.3"/>
|
||||||
|
<path d="M143.397 145.571C138.988 149.794 134.026 153.443 128.631 156.403C118.652 161.883 107.186 165 94.9973 165C82.8088 165 71.3487 161.886 61.3688 156.406C55.9745 153.448 51.0116 149.797 46.6002 145.571C51.0775 134.205 61.966 126.068 74.8116 125.611C75.1886 125.594 75.5714 125.585 75.9545 125.585H114.043C114.426 125.585 114.809 125.594 115.186 125.611C128.032 126.068 138.92 134.206 143.397 145.571Z" fill="#0E0D11"/>
|
||||||
|
<path d="M94.9973 147.674C94.9973 147.674 143.476 112.481 141.733 109.313C139.131 104.579 135.267 101.349 131.45 99.1579C125.043 95.4813 118.76 94.7354 118.76 94.7354L80.1704 127.487L94.9973 147.674Z" fill="#F87359"/>
|
||||||
|
<path d="M94.9973 147.674C94.9973 147.674 143.476 112.481 141.733 109.313C139.131 104.579 135.267 101.349 131.45 99.1578C135.353 103.476 139.1 110.045 133.335 115.807C132.404 116.739 131.379 117.37 130.287 117.749C126.476 119.074 122.93 121.065 120.008 123.848L94.9973 147.674Z" fill="#0E0D11"/>
|
||||||
|
<path d="M94.9973 147.674C94.9973 147.674 46.519 112.481 48.2611 109.313C50.8634 104.579 54.7276 101.349 58.5442 99.1579C64.9514 95.4813 71.2347 94.7354 71.2347 94.7354L94.9973 147.674Z" fill="#F87359"/>
|
||||||
|
<path d="M135.102 65.9344L121.749 73.8097V89.8293C121.749 93.5166 124.738 96.5059 128.426 96.5059C132.113 96.5059 135.102 93.5166 135.102 89.8293V65.9344Z" fill="#CCCCCC"/>
|
||||||
|
<path d="M54.8916 65.9344L68.2447 73.8097V89.8293C68.2447 93.5166 65.2555 96.5059 61.5682 96.5059C57.8809 96.5059 54.8916 93.5166 54.8916 89.8293V65.9344Z" fill="#CCCCCC"/>
|
||||||
|
<path d="M109.826 109.273V125.202C109.826 133.391 103.188 140.029 94.9984 140.029C86.8092 140.029 80.1707 133.391 80.1707 125.202V109.273H109.826Z" fill="#CCCCCC"/>
|
||||||
|
<path d="M128.012 64.663V92.6572C128.012 101.774 124.317 110.029 118.346 116C112.366 121.98 104.114 125.672 94.9973 125.672C76.7631 125.672 61.983 110.891 61.983 92.6572V64.663C61.983 63.1571 62.0831 61.6715 62.2802 60.2201C62.8859 55.703 64.4086 51.4773 66.6544 47.7317C72.4173 38.0974 117.58 38.0974 123.34 47.7317C125.586 51.4775 127.109 55.7032 127.714 60.2201C127.911 61.6715 128.012 63.1571 128.012 64.663Z" fill="#EDEDED"/>
|
||||||
|
<path d="M71.5475 92.6575V64.6635C71.5475 48.0552 83.8139 34.3155 99.7802 31.9979C98.2184 31.7709 96.6223 31.6487 94.997 31.6487C76.7639 31.6487 61.9821 46.4304 61.9821 64.6635V92.6575C61.9821 110.891 76.7639 125.672 94.997 125.672C96.622 125.672 98.2181 125.55 99.7805 125.323C83.8139 123.006 71.5475 109.266 71.5475 92.6575Z" fill="#CCCCCC"/>
|
||||||
|
<path d="M111.432 86.1581V79.8308C111.432 78.1806 110.094 76.8427 108.444 76.8427C106.794 76.8427 105.456 78.1803 105.456 79.8308V86.1581C105.456 87.8083 106.793 89.1462 108.444 89.1462C110.094 89.146 111.432 87.8083 111.432 86.1581Z" fill="#0E0D11"/>
|
||||||
|
<path d="M78.5642 79.8305V86.1579C78.5642 87.8081 79.9019 89.146 81.5523 89.146C83.2025 89.146 84.5405 87.8083 84.5405 86.1579V79.8305C84.5405 78.1803 83.2028 76.8424 81.5523 76.8424C79.9019 76.8427 78.5642 78.1803 78.5642 79.8305Z" fill="#0E0D11"/>
|
||||||
|
<path d="M109.48 82.8925C110.558 82.8925 111.432 82.0184 111.432 80.9401C111.432 79.8619 110.558 78.9878 109.48 78.9878C108.402 78.9878 107.528 79.8619 107.528 80.9401C107.528 82.0184 108.402 82.8925 109.48 82.8925Z" fill="#7F7D89"/>
|
||||||
|
<path d="M82.5887 82.8925C83.6669 82.8925 84.541 82.0184 84.541 80.9401C84.541 79.8619 83.6669 78.9878 82.5887 78.9878C81.5104 78.9878 80.6363 79.8619 80.6363 80.9401C80.6363 82.0184 81.5104 82.8925 82.5887 82.8925Z" fill="#7F7D89"/>
|
||||||
|
<path d="M107.297 86.6995C107.917 86.6995 108.419 86.197 108.419 85.577C108.419 84.9571 107.917 84.4546 107.297 84.4546C106.677 84.4546 106.175 84.9571 106.175 85.577C106.175 86.197 106.677 86.6995 107.297 86.6995Z" fill="#7F7D89"/>
|
||||||
|
<path d="M80.4086 86.6995C81.0285 86.6995 81.531 86.197 81.531 85.577C81.531 84.9571 81.0285 84.4546 80.4086 84.4546C79.7886 84.4546 79.2861 84.9571 79.2861 85.577C79.2861 86.197 79.7886 86.6995 80.4086 86.6995Z" fill="#7F7D89"/>
|
||||||
|
<path d="M69.2829 60.2204C69.2829 60.5652 69.2963 60.907 69.3231 61.2452C69.6409 65.2842 68.1812 69.2835 65.1182 71.9355C64.1609 72.7646 63.1095 73.4884 61.9827 74.0891V64.6635C61.9827 58.472 63.6857 52.6833 66.6541 47.7319C68.4484 49.7291 69.774 52.1548 70.4625 54.8378C69.7057 56.4746 69.2829 58.3003 69.2829 60.2204Z" fill="#0E0D11"/>
|
||||||
|
<path d="M128.012 64.6629V74.0885C126.885 73.4878 125.834 72.764 124.876 71.9349C121.814 69.2829 120.353 65.2836 120.671 61.2446C120.698 60.9064 120.711 60.5646 120.711 60.2198C120.711 58.2997 120.289 56.474 119.531 54.8369C120.22 52.1539 121.546 49.7283 123.34 47.7311C126.309 52.6828 128.012 58.4714 128.012 64.6629Z" fill="#0E0D11"/>
|
||||||
|
<path d="M73.9132 78.0136L85.9927 82.6837L88.6714 75.7552L76.5919 71.085L73.9132 78.0136Z" fill="#EDEDED"/>
|
||||||
|
<path d="M113.406 71.0863L101.326 75.7565L104.005 82.685L116.085 78.0148L113.406 71.0863Z" fill="#EDEDED"/>
|
||||||
|
<path d="M110.617 95.4572C110.617 100.789 107.946 105.497 103.866 108.314C101.346 110.057 98.2914 111.077 94.997 111.077C91.7026 111.077 88.6483 110.057 86.1283 108.314C82.0484 105.497 79.3769 100.788 79.3769 95.4572C80.8225 96.1801 82.3084 96.7973 83.8197 97.3086C85.4026 97.8429 87.014 98.2629 88.6396 98.5629C90.7396 98.9514 92.868 99.1458 94.9967 99.1458C97.1252 99.1458 99.2539 98.9514 101.354 98.5629C102.979 98.2629 104.591 97.8429 106.174 97.3086C107.686 96.797 109.171 96.1798 110.617 95.4572Z" fill="#0E0D11"/>
|
||||||
|
<path d="M103.866 108.314C101.346 110.057 98.2914 111.077 94.997 111.077C91.7026 111.077 88.6483 110.057 86.1283 108.314C88.6483 106.571 91.7026 105.551 94.997 105.551C98.2914 105.551 101.346 106.571 103.866 108.314Z" fill="#F87359"/>
|
||||||
|
<path d="M113.404 71.4581H76.5903L86.9166 79.2019H88.0555C90.0456 79.2019 91.6589 80.8149 91.6589 82.8052V88.3929C91.6589 90.2318 93.0974 91.809 94.9357 91.8426C96.8085 91.8768 98.3379 90.3688 98.3379 88.5037V82.8052C98.3379 80.8152 99.9511 79.2019 101.941 79.2019H103.078L113.404 71.4581Z" fill="#CCCCCC"/>
|
||||||
|
<path d="M106.174 97.3086C106.003 98.623 105.706 99.8658 105.38 100.954C104.649 103.4 103.76 105.077 103.76 105.077L102.226 100.923L101.354 98.5629C102.98 98.2629 104.591 97.8429 106.174 97.3086Z" fill="#F0F0F0"/>
|
||||||
|
<path d="M88.6401 98.5629L87.7687 100.923L86.2344 105.077C86.2344 105.077 85.3457 103.4 84.6143 100.954C84.2886 99.8658 83.9914 98.623 83.82 97.3086C85.4029 97.8429 87.0143 98.2629 88.6401 98.5629Z" fill="#F0F0F0"/>
|
||||||
|
<path d="M71.3799 73.6013L74.2056 69.2049C74.7098 68.4205 75.7549 68.193 76.5397 68.6972L88.1006 76.1281C89.6786 77.1423 88.6743 79.5887 86.8387 79.2015L72.4521 76.1669C71.2952 75.923 70.7406 74.5963 71.3799 73.6013Z" fill="#0E0D11"/>
|
||||||
|
<path d="M118.614 73.6013L115.789 69.2049C115.284 68.4205 114.239 68.193 113.455 68.6972L101.894 76.1281C100.316 77.1423 101.32 79.5887 103.155 79.2015L117.542 76.1669C118.699 75.923 119.254 74.5963 118.614 73.6013Z" fill="#0E0D11"/>
|
||||||
|
<path d="M98.6162 116.791H91.3783C90.642 116.791 90.0448 116.194 90.0448 115.458C90.0448 114.721 90.6417 114.124 91.3783 114.124H98.6162C99.3526 114.124 99.9498 114.721 99.9498 115.458C99.9495 116.195 99.3526 116.791 98.6162 116.791Z" fill="#CCCCCC"/>
|
||||||
|
<path d="M123.34 47.7315C117.58 38.0972 107.043 31.6487 94.997 31.6487C82.9543 31.6487 72.4171 38.0972 66.6541 47.7315C64.4084 51.4773 62.8856 55.703 62.2799 60.2199H69.2827C69.2827 53.1198 75.0399 47.3629 82.1397 47.3629C82.3122 47.3629 82.4842 47.3664 82.6551 47.3733C88.6833 47.6111 93.3791 52.7179 93.3791 58.751V60.5075C93.3791 61.4009 94.1034 62.1252 94.9967 62.1252C95.89 62.1252 96.6144 61.4009 96.6144 60.5075V58.751C96.6144 52.7179 101.31 47.6111 107.338 47.3733C107.509 47.3664 107.681 47.3629 107.854 47.3629C114.954 47.3629 120.711 53.1201 120.711 60.2199H127.714C127.109 55.703 125.586 51.4773 123.34 47.7315Z" fill="#0E0D11"/>
|
||||||
|
<path d="M94.9973 147.674C94.9973 147.674 46.519 112.481 48.2611 109.313C50.8634 104.579 54.7276 101.349 58.5442 99.158C54.642 103.476 50.8943 110.045 56.6597 115.808C57.591 116.739 58.6159 117.37 59.7074 117.749C63.5189 119.075 67.0645 121.065 69.9862 123.848L94.9973 147.674Z" fill="#0E0D11"/>
|
||||||
|
<path d="M106.604 145.612L95.788 149.62C95.2786 149.809 94.7184 149.809 94.2089 149.62L83.3934 145.612C81.9095 145.062 80.3317 146.16 80.3317 147.743V154.412C80.3317 155.994 81.9095 157.092 83.3934 156.542L94.2089 152.534C94.7184 152.345 95.2786 152.345 95.788 152.534L106.604 156.542C108.088 157.092 109.665 155.994 109.665 154.412V147.743C109.665 146.16 108.088 145.062 106.604 145.612Z" fill="#F87359"/>
|
||||||
|
<path d="M105.38 100.954C104.649 103.4 103.76 105.077 103.76 105.077L102.226 100.923C102.703 100.746 103.22 100.649 103.76 100.649C104.331 100.649 104.877 100.757 105.38 100.954Z" fill="#F87359"/>
|
||||||
|
<path d="M87.7687 100.923L86.2344 105.077C86.2344 105.077 85.3457 103.4 84.6143 100.954C85.1172 100.757 85.6629 100.649 86.2344 100.649C86.7742 100.649 87.2915 100.746 87.7687 100.923Z" fill="#F87359"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_511_171" x="0" y="0" width="190" height="190" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="10"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.06 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_511_171"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_511_171" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="clip0_511_171">
|
||||||
|
<rect width="140" height="140" fill="white" transform="translate(25 25)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 10 KiB |
9
public/marketplace/dracula-theme/theme.css
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[data-theme="dracula"] {
|
||||||
|
--background-color: #282a36;
|
||||||
|
--background-highlight: #44475a;
|
||||||
|
--accent-color: #4e5268;
|
||||||
|
--accent-color-brighter: #2d2f3c;
|
||||||
|
--text-color: #f8f8f2;
|
||||||
|
--text-color-accent: #dddddd;
|
||||||
|
--dropdown-background-color: #343b52;
|
||||||
|
}
|
||||||
BIN
public/marketplace/eruda/banner.png
Normal file
|
After Width: | Height: | Size: 312 KiB |
1
public/marketplace/eruda/eruda.js
Normal file
BIN
public/marketplace/nord-theme/logo.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
9
public/marketplace/nord-theme/theme.css
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[data-theme="nord"] {
|
||||||
|
--background-color: #2e3440;
|
||||||
|
--background-highlight: #3b4252;
|
||||||
|
--accent-color: #434c5e;
|
||||||
|
--accent-color-brighter: #4c566a;
|
||||||
|
--text-color: #f8f8f2;
|
||||||
|
--text-color-accent: #dddddd;
|
||||||
|
--dropdown-background-color: #3b4252;
|
||||||
|
}
|
||||||
9
public/marketplace/oled-theme/theme.css
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[data-theme="oled"] {
|
||||||
|
--background-color: #000;
|
||||||
|
--background-highlight: #111;
|
||||||
|
--accent-color: rgb(30 0 79);
|
||||||
|
--accent-color-brighter: rgb(60 0 155);
|
||||||
|
--text-color: #fff;
|
||||||
|
--text-color-accent: #dddddd;
|
||||||
|
--dropdown-background-color: #1a1a1a;
|
||||||
|
}
|
||||||
BIN
public/marketplace/oled-theme/theme.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
1
public/marketplace/scriptInjector/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
(()=>{async function i(e){let o=e.request.url,s=e.workerware.config;if(o.includes(self.__uv$config.prefix)){let r=self.__uv$config.decodeUrl(e.request.url.split(self.__uv$config.prefix)[1]);if(r==e.workerware.config.injectURL){console.log(`Injecting script into ${r}!`),console.log(s.injectURls);let n=(await e.uvResponse.text()).replace("</head>",`<script src="${s.injectURLs[0]}"><\/script><link rel="stylesheet" href="${s.injectURLs[1]}"></head>`);return new Response(n,{status:e.uvResponse.status,statusText:e.uvResponse.statusText,headers:e.uvResponse.headers})}return e.uvResponse}}self.scriptInjector={inject:i};})();
|
||||||
BIN
public/marketplace/synthwave84/logo.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
9
public/marketplace/synthwave84/theme.css
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[data-theme="synthwave84"] {
|
||||||
|
--background-color: #2a203a;
|
||||||
|
--background-highlight: #2e2342;
|
||||||
|
--accent-color: #1e1629;
|
||||||
|
--accent-color-brighter: #3e2e53;
|
||||||
|
--text-color: #c0bdc4;
|
||||||
|
--text-color-accent: #dddddd;
|
||||||
|
--dropdown-background-color: #231a30;
|
||||||
|
}
|
||||||
3
public/robots-allow.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
User-agent: *
|
||||||
|
Allow: *
|
||||||
|
Sitemap: https://aluu.xyz/sitemap-index.xml
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
User-agent: *
|
User-agent: *
|
||||||
Allow: *
|
Disallow: *
|
||||||
84
public/sw.js
|
|
@ -1,18 +1,74 @@
|
||||||
/*global UVServiceWorker,__uv$config*/
|
importScripts("/uv/uv.bundle.js", "/uv.config.js", "/workerware/workerware.js");
|
||||||
/*
|
importScripts( __uv$config.sw);
|
||||||
* Stock service worker script.
|
importScripts("/marketplace/scriptInjector/index.js")
|
||||||
* Users can provide their own sw.js if they need to extend the functionality of the service worker.
|
|
||||||
* Ideally, this will be registered under the scope in uv.config.js so it will not need to be modified.
|
|
||||||
* However, if a user changes the location of uv.bundle.js/uv.config.js or sw.js is not relative to them, they will need to modify this script locally.
|
|
||||||
*/
|
|
||||||
importScripts("/uv/uv.bundle.js");
|
|
||||||
importScripts("/uv.config.js");
|
|
||||||
importScripts(__uv$config.sw);
|
|
||||||
|
|
||||||
self.addEventListener("install", (event) => {
|
const uv = new UVServiceWorker();
|
||||||
self.skipWaiting();
|
const ww = new WorkerWare({
|
||||||
|
debug: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const sw = new UVServiceWorker();
|
function loadExtensionScripts() {
|
||||||
|
try {
|
||||||
|
let db = indexedDB.open("AluDB", 1);
|
||||||
|
db.onsuccess = () => {
|
||||||
|
try {
|
||||||
|
let transaction = db.result.transaction("InstalledExtensions", "readonly");
|
||||||
|
let store = transaction.objectStore("InstalledExtensions");
|
||||||
|
let request = store.getAll();
|
||||||
|
request.onsuccess = () => {
|
||||||
|
let extensions = request.result.filter((extension) => extension.type == "serviceWorker");
|
||||||
|
extensions.forEach((extension) => {
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
const contents = decoder.decode(extension.scriptCopy);
|
||||||
|
|
||||||
self.addEventListener("fetch", (event) => event.respondWith(sw.fetch(event)));
|
|
||||||
|
eval(contents);
|
||||||
|
const func = self[extension.entryNamespace][extension.entryFunc];
|
||||||
|
switch (extension.type) {
|
||||||
|
case "serviceWorker":
|
||||||
|
// Loads the function to be added as a middleware into global scope.
|
||||||
|
|
||||||
|
ww.use({
|
||||||
|
function: self[extension.entryNamespace][extension.entryFunc],
|
||||||
|
name: extension.title,
|
||||||
|
events: ["fetch"],
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "page":
|
||||||
|
console.log("Calling " + extension.entryFunc);
|
||||||
|
func();
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
console.error("Failed to open IndexedDB");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Failed load extension scripts: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
loadExtensionScripts();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Failed to load extension scripts: ${err}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
self.addEventListener("fetch", async (event) => {
|
||||||
|
event.respondWith(
|
||||||
|
(async () => {
|
||||||
|
let mwResponse = await ww.run(event)();
|
||||||
|
if (mwResponse.includes(null)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.request.url.startsWith(location.origin + __uv$config.prefix)) {
|
||||||
|
return await uv.fetch(event);
|
||||||
|
}
|
||||||
|
return await fetch(event.request);
|
||||||
|
})()
|
||||||
|
);
|
||||||
|
});
|
||||||
4924
public/unity/UnityLoader.js
Normal file
423
public/unity/index.css
Normal file
|
|
@ -0,0 +1,423 @@
|
||||||
|
*,:before,:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-width: 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #e5e7eb
|
||||||
|
}
|
||||||
|
|
||||||
|
:before,:after {
|
||||||
|
--tw-content: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.5;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
font-family: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";
|
||||||
|
font-feature-settings: normal;
|
||||||
|
font-variation-settings: normal
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
line-height: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
height: 0;
|
||||||
|
color: inherit;
|
||||||
|
border-top-width: 1px
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr:where([title]) {
|
||||||
|
-webkit-text-decoration: underline dotted;
|
||||||
|
text-decoration: underline dotted
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,h2,h3,h4,h5,h6 {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
b,strong {
|
||||||
|
font-weight: bolder
|
||||||
|
}
|
||||||
|
|
||||||
|
code,kbd,samp,pre {
|
||||||
|
font-family: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;
|
||||||
|
font-size: 1em
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%
|
||||||
|
}
|
||||||
|
|
||||||
|
sub,sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -.25em
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -.5em
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
text-indent: 0;
|
||||||
|
border-color: inherit;
|
||||||
|
border-collapse: collapse
|
||||||
|
}
|
||||||
|
|
||||||
|
button,input,optgroup,select,textarea {
|
||||||
|
font-family: inherit;
|
||||||
|
font-feature-settings: inherit;
|
||||||
|
font-variation-settings: inherit;
|
||||||
|
font-size: 100%;
|
||||||
|
font-weight: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
button,select {
|
||||||
|
text-transform: none
|
||||||
|
}
|
||||||
|
|
||||||
|
button,[type=button],[type=reset],[type=submit] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none
|
||||||
|
}
|
||||||
|
|
||||||
|
:-moz-focusring {
|
||||||
|
outline: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
:-moz-ui-invalid {
|
||||||
|
box-shadow: none
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-inner-spin-button,::-webkit-outer-spin-button {
|
||||||
|
height: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=search] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
outline-offset: -2px
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
font: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre {
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ol,ul,menu {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog {
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
input::-moz-placeholder,textarea::-moz-placeholder {
|
||||||
|
opacity: 1;
|
||||||
|
color: #9ca3af
|
||||||
|
}
|
||||||
|
|
||||||
|
input::placeholder,textarea::placeholder {
|
||||||
|
opacity: 1;
|
||||||
|
color: #9ca3af
|
||||||
|
}
|
||||||
|
|
||||||
|
button,[role=button] {
|
||||||
|
cursor: pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
:disabled {
|
||||||
|
cursor: default
|
||||||
|
}
|
||||||
|
|
||||||
|
img,svg,video,canvas,audio,iframe,embed,object {
|
||||||
|
display: block;
|
||||||
|
vertical-align: middle
|
||||||
|
}
|
||||||
|
|
||||||
|
img,video {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
*,:before,:after {
|
||||||
|
--tw-border-spacing-x: 0;
|
||||||
|
--tw-border-spacing-y: 0;
|
||||||
|
--tw-translate-x: 0;
|
||||||
|
--tw-translate-y: 0;
|
||||||
|
--tw-rotate: 0;
|
||||||
|
--tw-skew-x: 0;
|
||||||
|
--tw-skew-y: 0;
|
||||||
|
--tw-scale-x: 1;
|
||||||
|
--tw-scale-y: 1;
|
||||||
|
--tw-pan-x: ;
|
||||||
|
--tw-pan-y: ;
|
||||||
|
--tw-pinch-zoom: ;
|
||||||
|
--tw-scroll-snap-strictness: proximity;
|
||||||
|
--tw-gradient-from-position: ;
|
||||||
|
--tw-gradient-via-position: ;
|
||||||
|
--tw-gradient-to-position: ;
|
||||||
|
--tw-ordinal: ;
|
||||||
|
--tw-slashed-zero: ;
|
||||||
|
--tw-numeric-figure: ;
|
||||||
|
--tw-numeric-spacing: ;
|
||||||
|
--tw-numeric-fraction: ;
|
||||||
|
--tw-ring-inset: ;
|
||||||
|
--tw-ring-offset-width: 0px;
|
||||||
|
--tw-ring-offset-color: #fff;
|
||||||
|
--tw-ring-color: rgb(59 130 246 / .5);
|
||||||
|
--tw-ring-offset-shadow: 0 0 #0000;
|
||||||
|
--tw-ring-shadow: 0 0 #0000;
|
||||||
|
--tw-shadow: 0 0 #0000;
|
||||||
|
--tw-shadow-colored: 0 0 #0000;
|
||||||
|
--tw-blur: ;
|
||||||
|
--tw-brightness: ;
|
||||||
|
--tw-contrast: ;
|
||||||
|
--tw-grayscale: ;
|
||||||
|
--tw-hue-rotate: ;
|
||||||
|
--tw-invert: ;
|
||||||
|
--tw-saturate: ;
|
||||||
|
--tw-sepia: ;
|
||||||
|
--tw-drop-shadow: ;
|
||||||
|
--tw-backdrop-blur: ;
|
||||||
|
--tw-backdrop-brightness: ;
|
||||||
|
--tw-backdrop-contrast: ;
|
||||||
|
--tw-backdrop-grayscale: ;
|
||||||
|
--tw-backdrop-hue-rotate: ;
|
||||||
|
--tw-backdrop-invert: ;
|
||||||
|
--tw-backdrop-opacity: ;
|
||||||
|
--tw-backdrop-saturate: ;
|
||||||
|
--tw-backdrop-sepia:
|
||||||
|
}
|
||||||
|
|
||||||
|
::backdrop {
|
||||||
|
--tw-border-spacing-x: 0;
|
||||||
|
--tw-border-spacing-y: 0;
|
||||||
|
--tw-translate-x: 0;
|
||||||
|
--tw-translate-y: 0;
|
||||||
|
--tw-rotate: 0;
|
||||||
|
--tw-skew-x: 0;
|
||||||
|
--tw-skew-y: 0;
|
||||||
|
--tw-scale-x: 1;
|
||||||
|
--tw-scale-y: 1;
|
||||||
|
--tw-pan-x: ;
|
||||||
|
--tw-pan-y: ;
|
||||||
|
--tw-pinch-zoom: ;
|
||||||
|
--tw-scroll-snap-strictness: proximity;
|
||||||
|
--tw-gradient-from-position: ;
|
||||||
|
--tw-gradient-via-position: ;
|
||||||
|
--tw-gradient-to-position: ;
|
||||||
|
--tw-ordinal: ;
|
||||||
|
--tw-slashed-zero: ;
|
||||||
|
--tw-numeric-figure: ;
|
||||||
|
--tw-numeric-spacing: ;
|
||||||
|
--tw-numeric-fraction: ;
|
||||||
|
--tw-ring-inset: ;
|
||||||
|
--tw-ring-offset-width: 0px;
|
||||||
|
--tw-ring-offset-color: #fff;
|
||||||
|
--tw-ring-color: rgb(59 130 246 / .5);
|
||||||
|
--tw-ring-offset-shadow: 0 0 #0000;
|
||||||
|
--tw-ring-shadow: 0 0 #0000;
|
||||||
|
--tw-shadow: 0 0 #0000;
|
||||||
|
--tw-shadow-colored: 0 0 #0000;
|
||||||
|
--tw-blur: ;
|
||||||
|
--tw-brightness: ;
|
||||||
|
--tw-contrast: ;
|
||||||
|
--tw-grayscale: ;
|
||||||
|
--tw-hue-rotate: ;
|
||||||
|
--tw-invert: ;
|
||||||
|
--tw-saturate: ;
|
||||||
|
--tw-sepia: ;
|
||||||
|
--tw-drop-shadow: ;
|
||||||
|
--tw-backdrop-blur: ;
|
||||||
|
--tw-backdrop-brightness: ;
|
||||||
|
--tw-backdrop-contrast: ;
|
||||||
|
--tw-backdrop-grayscale: ;
|
||||||
|
--tw-backdrop-hue-rotate: ;
|
||||||
|
--tw-backdrop-invert: ;
|
||||||
|
--tw-backdrop-opacity: ;
|
||||||
|
--tw-backdrop-saturate: ;
|
||||||
|
--tw-backdrop-sepia:
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.container {
|
||||||
|
max-width:640px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.container {
|
||||||
|
max-width:768px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.container {
|
||||||
|
max-width:1024px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1280px) {
|
||||||
|
.container {
|
||||||
|
max-width:1280px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1536px) {
|
||||||
|
.container {
|
||||||
|
max-width:1536px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-5 {
|
||||||
|
height: 1.25rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-full {
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-10 {
|
||||||
|
width: 2.5rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-5 {
|
||||||
|
width: 1.25rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-full {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-spin {
|
||||||
|
animation: spin 1s linear infinite
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-center {
|
||||||
|
align-items: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-5 {
|
||||||
|
gap: 1.25rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.border {
|
||||||
|
border-width: 1px
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-slate-800 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(30 41 59 / var(--tw-bg-opacity))
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-white {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(255 255 255 / var(--tw-bg-opacity))
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-slate-200 {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(226 232 240 / var(--tw-text-opacity))
|
||||||
|
}
|
||||||
|
|
||||||
|
.underline {
|
||||||
|
text-decoration-line: underline
|
||||||
|
}
|
||||||
|
|
||||||
|
.opacity-25 {
|
||||||
|
opacity: .25
|
||||||
|
}
|
||||||
|
|
||||||
|
.opacity-75 {
|
||||||
|
opacity: .75
|
||||||
|
}
|
||||||
|
|
||||||
|
#gameContainer {
|
||||||
|
overflow: hidden
|
||||||
|
}
|
||||||
35
public/unity/instantiateUnity.js
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
const a = window.location.pathname.split("/").pop();
|
||||||
|
|
||||||
|
if (a && UnityLoader) {
|
||||||
|
let t = function () {
|
||||||
|
setTimeout(() => {
|
||||||
|
n.Module.canvas.style.height = "100%"
|
||||||
|
}, 1000)
|
||||||
|
requestAnimationFrame(t)
|
||||||
|
};
|
||||||
|
// UnityLoader.Error.handler = e => {
|
||||||
|
// throw document.querySelector("#loader").classList.add("hidden"),
|
||||||
|
// document.querySelector("#error").classList.remove("hidden"),
|
||||||
|
// e
|
||||||
|
// };
|
||||||
|
const n = UnityLoader.instantiate("gameContainer", `/games/${a}/data.json`, {
|
||||||
|
onProgress: (e, r) => { },
|
||||||
|
Module: {
|
||||||
|
onRuntimeInitialized: () => {
|
||||||
|
document.querySelector("#loader").classList.add("hidden"),
|
||||||
|
document.querySelector("#gameContainer").classList.remove("hidden")
|
||||||
|
}
|
||||||
|
,
|
||||||
|
wasmRequest: function (e, r) {
|
||||||
|
e(this.wasmBinary).then(function (o) {
|
||||||
|
r(o.instance)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
print: () => { },
|
||||||
|
printErr: () => { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
requestAnimationFrame(t)
|
||||||
|
} else
|
||||||
|
document.querySelector("#loader").classList.add("hidden"),
|
||||||
|
document.querySelector("#error").classList.remove("hidden");
|
||||||
32
public/unity/preload.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
(function() {
|
||||||
|
const t = document.createElement("link").relList;
|
||||||
|
if (t && t.supports && t.supports("modulepreload"))
|
||||||
|
return;
|
||||||
|
for (const e of document.querySelectorAll('link[rel="modulepreload"]'))
|
||||||
|
i(e);
|
||||||
|
new MutationObserver(e=>{
|
||||||
|
for (const r of e)
|
||||||
|
if (r.type === "childList")
|
||||||
|
for (const o of r.addedNodes)
|
||||||
|
o.tagName === "LINK" && o.rel === "modulepreload" && i(o)
|
||||||
|
}
|
||||||
|
).observe(document, {
|
||||||
|
childList: !0,
|
||||||
|
subtree: !0
|
||||||
|
});
|
||||||
|
function s(e) {
|
||||||
|
const r = {};
|
||||||
|
return e.integrity && (r.integrity = e.integrity),
|
||||||
|
e.referrerPolicy && (r.referrerPolicy = e.referrerPolicy),
|
||||||
|
e.crossOrigin === "use-credentials" ? r.credentials = "include" : e.crossOrigin === "anonymous" ? r.credentials = "omit" : r.credentials = "same-origin",
|
||||||
|
r
|
||||||
|
}
|
||||||
|
function i(e) {
|
||||||
|
if (e.ep)
|
||||||
|
return;
|
||||||
|
e.ep = !0;
|
||||||
|
const r = s(e);
|
||||||
|
fetch(e.href, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)();
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
/*global Ultraviolet*/
|
/*global Ultraviolet*/
|
||||||
self.__uv$config = {
|
self.__uv$config = {
|
||||||
prefix: "/service/",
|
prefix: "/service/",
|
||||||
bare: "/bare/",
|
|
||||||
encodeUrl: Ultraviolet.codec.xor.encode,
|
encodeUrl: Ultraviolet.codec.xor.encode,
|
||||||
decodeUrl: Ultraviolet.codec.xor.decode,
|
decodeUrl: Ultraviolet.codec.xor.decode,
|
||||||
handler: "/uv/uv.handler.js",
|
handler: "/uv/uv.handler.js",
|
||||||
client: "/uv/uv.client.js",
|
client: "/uv/uv.client.js",
|
||||||
bundle: "/uv/uv.bundle.js",
|
bundle: "/uv/uv.bundle.js",
|
||||||
config: "/uv/uv.config.js",
|
config: "/uv.config.js",
|
||||||
sw: "/uv/uv.sw.js",
|
sw: "/uv/uv.sw.js",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
BIN
public/varela-latin-ext.woff2
Normal file
BIN
public/varela-latin.woff2
Normal file
21
public/varela-round.css
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: "Varela Round";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(varela-latin-ext.woff2) format("woff2");
|
||||||
|
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
|
||||||
|
U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: "Varela Round";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(varela-latin.woff2) format("woff2");
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
|
||||||
|
U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
|
||||||
|
U+FFFD;
|
||||||
|
}
|
||||||
6
public/workerware/WWError.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
class WWError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.name = "[WorkerWare Exception]";
|
||||||
|
}
|
||||||
|
}
|
||||||
168
public/workerware/workerware.js
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
importScripts("/workerware/WWError.js");
|
||||||
|
const dbg = console.log.bind(console, "[WorkerWare]");
|
||||||
|
const time = console.time.bind(console, "[WorkerWare]");
|
||||||
|
const timeEnd = console.timeEnd.bind(console, "[WorkerWare]");
|
||||||
|
|
||||||
|
/*
|
||||||
|
OPTS:
|
||||||
|
debug - Enables debug logging.
|
||||||
|
randomNames - Generate random names for middlewares.
|
||||||
|
timing - Logs timing for each middleware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const defaultOpt = {
|
||||||
|
debug: false,
|
||||||
|
randomNames: false,
|
||||||
|
timing: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const validEvents = [
|
||||||
|
"abortpayment",
|
||||||
|
"activate",
|
||||||
|
"backgroundfetchabort",
|
||||||
|
"backgroundfetchclick",
|
||||||
|
"backgroundfetchfail",
|
||||||
|
"backgroundfetchsuccess",
|
||||||
|
"canmakepayment",
|
||||||
|
"contentdelete",
|
||||||
|
"cookiechange",
|
||||||
|
"fetch",
|
||||||
|
"install",
|
||||||
|
"message",
|
||||||
|
"messageerror",
|
||||||
|
"notificationclick",
|
||||||
|
"notificationclose",
|
||||||
|
"paymentrequest",
|
||||||
|
"periodicsync",
|
||||||
|
"push",
|
||||||
|
"pushsubscriptionchange",
|
||||||
|
"sync",
|
||||||
|
];
|
||||||
|
|
||||||
|
class WorkerWare {
|
||||||
|
constructor(opt) {
|
||||||
|
this._opt = Object.assign({}, defaultOpt, opt);
|
||||||
|
this._middlewares = [];
|
||||||
|
}
|
||||||
|
info() {
|
||||||
|
return {
|
||||||
|
version: "0.1.0",
|
||||||
|
middlewares: this._middlewares,
|
||||||
|
options: this._opt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
use(middleware) {
|
||||||
|
let validateMW = this.validateMiddleware(middleware);
|
||||||
|
if (validateMW.error) throw new WWError(validateMW.error);
|
||||||
|
// This means the middleware is an anonymous function, or the user is silly and named their function "function"
|
||||||
|
if (middleware.function.name == "function") middleware.name = crypto.randomUUID();
|
||||||
|
if (!middleware.name) middleware.name = middleware.function.name;
|
||||||
|
if (this._opt.randomNames) middleware.name = crypto.randomUUID();
|
||||||
|
if (this._opt.debug) dbg("Adding middleware:", middleware.name);
|
||||||
|
this._middlewares.push(middleware);
|
||||||
|
}
|
||||||
|
// Run all middlewares for the event type passed in.
|
||||||
|
run(event) {
|
||||||
|
const middlewares = this._middlewares;
|
||||||
|
const returnList = [];
|
||||||
|
let fn = async () => {
|
||||||
|
for (let i = 0; i < middlewares.length; i++) {
|
||||||
|
if (middlewares[i].events.includes(event.type)) {
|
||||||
|
if (this._opt.timing) console.time(middlewares[i].name);
|
||||||
|
// Add the configuration to the event object.
|
||||||
|
event.workerware = {
|
||||||
|
config: middlewares[i].configuration || {},
|
||||||
|
};
|
||||||
|
if (!middlewares[i].explicitCall) {
|
||||||
|
let res = await middlewares[i].function(event);
|
||||||
|
if (this._opt.timing) console.timeEnd(middlewares[i].name);
|
||||||
|
returnList.push(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnList;
|
||||||
|
};
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
deleteByName(middlewareID) {
|
||||||
|
if (this._opt.debug) dbg("Deleting middleware:", middlewareID);
|
||||||
|
this._middlewares = this._middlewares.filter((mw) => mw.name !== middlewareID);
|
||||||
|
}
|
||||||
|
deleteByEvent(middlewareEvent) {
|
||||||
|
if (this._opt.debug) dbg("Deleting middleware by event:", middlewareEvent);
|
||||||
|
this._middlewares = this._middlewares.filter((mw) => !mw.events.includes(middlewareEvent));
|
||||||
|
}
|
||||||
|
get() {
|
||||||
|
return this._middlewares;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Run a single middleware by ID.
|
||||||
|
This assumes that the user knows what they're doing, and is running the middleware on an event that it's supposed to run on.
|
||||||
|
*/
|
||||||
|
runMW(name, event) {
|
||||||
|
const middlewares = this._middlewares;
|
||||||
|
if (this._opt.debug) dbg("Running middleware:", name);
|
||||||
|
// if (middlewares.includes(name)) {
|
||||||
|
// return middlewares[name](event);
|
||||||
|
// } else {
|
||||||
|
// throw new WWError("Middleware not found!");
|
||||||
|
// }
|
||||||
|
let didCall = false;
|
||||||
|
for (let i = 0; i < middlewares.length; i++) {
|
||||||
|
if (middlewares[i].name == name) {
|
||||||
|
didCall = true;
|
||||||
|
event.workerware = {
|
||||||
|
config: middlewares[i].configuration || {},
|
||||||
|
}
|
||||||
|
if (this._opt.timing) console.time(middlewares[i].name);
|
||||||
|
let call = middlewares[i].function(event);
|
||||||
|
if (this._opt.timing) console.timeEnd(middlewares[i].name);
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!didCall) {
|
||||||
|
throw new WWError("Middleware not found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// type middlewareManifest = {
|
||||||
|
// function: Function,
|
||||||
|
// name?: string,
|
||||||
|
// events: string[], // Should be a union of validEvents.
|
||||||
|
// configuration?: Object // Optional configuration for the middleware.
|
||||||
|
// }
|
||||||
|
validateMiddleware(middleware) {
|
||||||
|
if (!middleware.function)
|
||||||
|
return {
|
||||||
|
error: "middleware.function is required",
|
||||||
|
};
|
||||||
|
if (typeof middleware.function !== "function")
|
||||||
|
return {
|
||||||
|
error: "middleware.function must be typeof function",
|
||||||
|
};
|
||||||
|
if (typeof middleware.configuration !== "object" && middleware.configuration !== undefined) {
|
||||||
|
return {
|
||||||
|
error: "middleware.configuration must be typeof object",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!middleware.events)
|
||||||
|
return {
|
||||||
|
error: "middleware.events is required",
|
||||||
|
};
|
||||||
|
if (!Array.isArray(middleware.events))
|
||||||
|
return {
|
||||||
|
error: "middleware.events must be an array",
|
||||||
|
};
|
||||||
|
if (middleware.events.some((ev) => !validEvents.includes(ev)))
|
||||||
|
return {
|
||||||
|
error: "Invalid event type! Must be one of the following: " + validEvents.join(", "),
|
||||||
|
};
|
||||||
|
if (middleware.explicitCall && typeof middleware.explicitCall !== "boolean") {
|
||||||
|
return {
|
||||||
|
error: "middleware.explicitCall must be typeof boolean",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
error: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/alu.d.ts
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
export declare global {
|
||||||
|
// Hacky way to not have to cast the "event" type that lib.dom has to CustomEvent, which is what we actually use.
|
||||||
|
interface Document {
|
||||||
|
addEventListener(type: "setting-tabLoad", listener: (this: Document, ev: CustomEvent) => any, options?: boolean | AddEventListenerOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Alu {
|
||||||
|
let store: AluStore;
|
||||||
|
let eventList: Record<string, EventListener>;
|
||||||
|
let settings: {
|
||||||
|
loadedContentStorage: Record<string, string>;
|
||||||
|
currentTab: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DefaultKeys = {
|
||||||
|
[key: string]: Key;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Key = Record<string, string | KeyObj>;
|
||||||
|
|
||||||
|
type KeyObj = {
|
||||||
|
name: string;
|
||||||
|
value?: string;
|
||||||
|
icon?: string;
|
||||||
|
isCustom?: boolean;
|
||||||
|
};
|
||||||
|
type ValidStoreKeys = "proxy" | "search" | "openpage" | "wisp" | "bareUrl" | "transport" | "theme" | "lang" | "cloak";
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/components/FaqCard.astro
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
export interface Props {
|
||||||
|
large?: boolean;
|
||||||
|
}
|
||||||
|
const { large } = Astro.props;
|
||||||
|
|
||||||
|
const classlist = "faq-card" + (large ? " faq-large" : "");
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class={classlist}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.faq-card {
|
||||||
|
background-color: var(--dropdown-background-color);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
color: var(--text-color);
|
||||||
|
box-shadow: 5px 5px 5px color-mix(in srgb, var(--background-color), black 40%);
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.faq-card {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.faq-large {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
---
|
|
||||||
import { getLangFromUrl, useTranslations } from "../i18n/utils";
|
|
||||||
import WaveSVG from "./WaveSVG.astro";
|
|
||||||
const lang = getLangFromUrl(Astro.url);
|
|
||||||
const t = useTranslations(lang);
|
|
||||||
---
|
|
||||||
|
|
||||||
<div class="footer">
|
|
||||||
<div class="wave-svg-container">
|
|
||||||
<WaveSVG />
|
|
||||||
</div>
|
|
||||||
<div class="footer-top">
|
|
||||||
<div class="footer-title">
|
|
||||||
<h2>{t("footer.brand")}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-madeby">
|
|
||||||
<a href="https://wearr.dev">{t("footer.madeWithLove")}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="footer-bottom">
|
|
||||||
<div class="footer-links">
|
|
||||||
<a href="https://titaniumnetwork.org">{t("footer.poweredBy")}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-copyright">
|
|
||||||
<p>© {t("footer.aluProject")} 2024</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.wave-svg-container {
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
z-index: -1;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 300px;
|
|
||||||
filter: brightness(1.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
color: var(--text-color);
|
|
||||||
position: relative;
|
|
||||||
padding-top: 100px;
|
|
||||||
gap: 50px;
|
|
||||||
}
|
|
||||||
.footer-top,
|
|
||||||
.footer-bottom {
|
|
||||||
width: 90%;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-title {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,32 +1,51 @@
|
||||||
---
|
---
|
||||||
const { name, image, slugName } = Astro.props;
|
const { game } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="game">
|
<div class="game" data-name={game.name} data-id={game.slug}>
|
||||||
<a href=`/games/${slugName || name}`>
|
<img class="pin-icon" src="/img/games/pin-outline.svg" />
|
||||||
<img class="game-img" src={image} alt="" />
|
<a class="game-link" href=`/game/${game.slug}`>
|
||||||
|
<img alt={game.name} class="game-img" src={game.image} alt="" />
|
||||||
|
<p class="game-title">{game.name}</p>
|
||||||
</a>
|
</a>
|
||||||
<p class="game-title">{name}</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.game {
|
.game {
|
||||||
|
position: relative;
|
||||||
|
background-color: var(--accent-color);
|
||||||
border: 2px solid var(--text-color);
|
border: 2px solid var(--text-color);
|
||||||
padding: 1rem;
|
padding: 1.2rem;
|
||||||
|
padding-bottom: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-radius: 15px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
.game-img {
|
.game-img {
|
||||||
width: 128px;
|
width: 128px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-link {
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-title {
|
.game-title {
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
max-width: 125px;
|
font-size: 18px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pin-icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 2px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
---
|
|
||||||
import { getLangFromUrl, useTranslations } from "../i18n/utils";
|
|
||||||
const lang = getLangFromUrl(Astro.url);
|
|
||||||
const t = useTranslations(lang);
|
|
||||||
---
|
|
||||||
|
|
||||||
<div class="top-header">
|
|
||||||
<div id="title-background" class="title-background">
|
|
||||||
<div class="left">
|
|
||||||
<a href={`/${lang}/`} class="header-item">{t("nav.brand")}</a>
|
|
||||||
</div>
|
|
||||||
<div class="right">
|
|
||||||
<a href={`/${lang}/games/`} class="header-item">{t("nav.games")}</a>
|
|
||||||
<a href={`/${lang}/settings/`} class="header-item">{t("nav.settings")}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.top-header {
|
|
||||||
display: flex;
|
|
||||||
box-sizing: border-box;
|
|
||||||
transition: 250ms ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-background {
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding-inline: 40px;
|
|
||||||
height: 70px;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 1.05rem;
|
|
||||||
list-style-type: none;
|
|
||||||
border: none;
|
|
||||||
z-index: 10;
|
|
||||||
border-bottom-left-radius: 5px;
|
|
||||||
border-bottom-right-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left,
|
|
||||||
.right {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-item {
|
|
||||||
color: var(--text-color);
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 22px;
|
|
||||||
transition: 250ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-item:hover {
|
|
||||||
color: var(--text-color-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1003px) {
|
|
||||||
.title-background {
|
|
||||||
width: 500%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
---
|
|
||||||
const { inputName, defaultTextContent, height, placeholder } = Astro.props;
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
inputName: string;
|
|
||||||
defaultTextContent?: string;
|
|
||||||
height: string;
|
|
||||||
placeholder?: string;
|
|
||||||
}
|
|
||||||
---
|
|
||||||
|
|
||||||
<input
|
|
||||||
style={`height: ${height}`}
|
|
||||||
id={inputName + "-input"}
|
|
||||||
placeholder={placeholder || ""}
|
|
||||||
value={defaultTextContent || ""}
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
input {
|
|
||||||
width: 100%;
|
|
||||||
border: 2px solid var(--background-highlight);
|
|
||||||
border-radius: 10px;
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
color: var(--text-color);
|
|
||||||
transition: 0.1s ease-in-out;
|
|
||||||
}
|
|
||||||
input:focus {
|
|
||||||
outline: none;
|
|
||||||
border: 2px solid var(--text-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
29
src/components/LoadingSpinner.astro
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<img src="/favicon.svg" class="load-img" />
|
||||||
|
<svg class="loading-spinner" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle class="full-circle" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
|
<path class="indicator" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loading-spinner {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
.load-img {
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
margin: 0.5rem;
|
||||||
|
}
|
||||||
|
.full-circle {
|
||||||
|
opacity: 25%;
|
||||||
|
}
|
||||||
|
.indicator {
|
||||||
|
opacity: 75%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,45 +1,112 @@
|
||||||
<script src="/uv/uv.bundle.js" transition:persist></script>
|
|
||||||
<script src="/uv.config.js" transition:persist></script>
|
|
||||||
<script>
|
<script>
|
||||||
//@ts-nocheck
|
import { TransportMgr, initTransport } from "./ts/TransportManager";
|
||||||
let form = document.querySelector("form");
|
import "notyf/notyf.min.css";
|
||||||
let input = document.querySelector("input");
|
import { Notyf } from "notyf";
|
||||||
window.navigator.serviceWorker.register("/sw.js", {
|
import EventMgr from "./ts/EventMgr";
|
||||||
scope: window.__uv$config.prefix,
|
|
||||||
});
|
const form = document.querySelector("form");
|
||||||
document.addEventListener("astro:after-swap", initForm);
|
let input = document.querySelector("input")!;
|
||||||
|
EventMgr.listen("astro:after-swap", initForm);
|
||||||
function initForm() {
|
function initForm() {
|
||||||
let formEle = document.querySelector("form");
|
const formEle = document.querySelector("form") as HTMLFormElement;
|
||||||
input = document.querySelector("input");
|
input = document.querySelector("input") as HTMLInputElement;
|
||||||
if (formEle) formEle.addEventListener("submit", formEventListener);
|
if (formEle) EventMgr.listen("submit", formEventListener, formEle);
|
||||||
}
|
}
|
||||||
if (form) {
|
if (form) {
|
||||||
form.addEventListener("submit", formEventListener);
|
form.addEventListener("submit", formEventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function formEventListener(event) {
|
setInterval(() => {
|
||||||
event.preventDefault();
|
const iframe = document.getElementById("proxy-frame") as HTMLIFrameElement;
|
||||||
let loadingContent = document.getElementById("loading-content");
|
if (iframe && iframe.src != "") {
|
||||||
loadingContent.style.opacity = 1;
|
updateProxiedFavicon(iframe);
|
||||||
|
updateTopbarTitle(iframe);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
async function getProxyURL() {
|
||||||
|
const preference = Alu.store.get("proxy").value;
|
||||||
let url = input.value.trim();
|
let url = input.value.trim();
|
||||||
if (!isUrl(url)) url = getSearchEngine() + url;
|
if (!isUrl(url)) url = getSearchEngine() + url;
|
||||||
else if (!(url.startsWith("https://") || url.startsWith("http://"))) url = "http://" + url;
|
if (preference === "ultraviolet") {
|
||||||
|
return window.__uv$config.prefix + window.__uv$config.encodeUrl(url);
|
||||||
|
} else if (preference == "rammerhead") {
|
||||||
|
// Check if rammerhead-session exists in cookies
|
||||||
|
const rammerheadSession = getCookie("rammerhead-session");
|
||||||
|
if (!rammerheadSession) {
|
||||||
|
const session = await fetch("/newsession");
|
||||||
|
const sessionID = await session.text();
|
||||||
|
await fetch("/editsession?id=" + sessionID + "&enableShuffling=0");
|
||||||
|
// Now save it in a cookie that expires in 72 hours.
|
||||||
|
document.cookie = `rammerhead-session=${sessionID}; max-age=${60 * 60 * 72}; path=/`;
|
||||||
|
}
|
||||||
|
return `/${getCookie("rammerhead-session")}/${url}`;
|
||||||
|
} else {
|
||||||
|
// Default to UV
|
||||||
|
return window.__uv$config.prefix + window.__uv$config.encodeUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let iframe = document.getElementById("proxy-frame");
|
function getUVProxyURL(frame: HTMLIFrameElement) {
|
||||||
let preference = getProxyPreference();
|
return window.__uv$config.decodeUrl(frame.contentWindow!.location.href.split("/service/")[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadProxyContent(): Promise<void> {
|
||||||
|
const loadingContent = document.getElementById("loading-content") as HTMLElement;
|
||||||
|
if (loadingContent) loadingContent.style.opacity = "1";
|
||||||
|
await initTransport();
|
||||||
|
// The setTimeout is because service workers are a little silly and can take a while longer to register despite .then being called, which causes a bug on the first load.
|
||||||
|
setTimeout(async () => {
|
||||||
|
const openWith = Alu.store.get("openpage");
|
||||||
|
const proxy = Alu.store.get("proxy");
|
||||||
|
let url = input!.value.trim();
|
||||||
|
if (!isUrl(url)) url = getSearchEngine() + url;
|
||||||
|
else if (!(url.startsWith("https://") || url.startsWith("http://"))) url = "http://" + url;
|
||||||
|
if (openWith) {
|
||||||
|
if (openWith.value === "newTab" || proxy.value === "rammerhead") {
|
||||||
|
window.open(await getProxyURL(), "_blank");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (openWith.value === "about:blank") {
|
||||||
|
// Open about:blank window and inject iframe into it
|
||||||
|
const newWindow = window.open("about:blank", "_blank");
|
||||||
|
const newWindowDocument = newWindow!.document;
|
||||||
|
const iframe = newWindowDocument.createElement("iframe");
|
||||||
|
iframe.src = await getProxyURL();
|
||||||
|
// Inject css into the iframe
|
||||||
|
const css = newWindowDocument.createElement("link");
|
||||||
|
css.rel = "stylesheet";
|
||||||
|
css.href = "/iframe.css";
|
||||||
|
newWindowDocument.head.appendChild(css);
|
||||||
|
newWindowDocument.body.appendChild(iframe);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const iframe = document.getElementById("proxy-frame") as HTMLIFrameElement;
|
||||||
|
const topbar = document.getElementById("top-bar") as HTMLDivElement;
|
||||||
|
const closeButton = document.getElementById("nav-close")!;
|
||||||
|
const backwardsButton = document.getElementById("nav-backwards")!;
|
||||||
|
const forwardsButton = document.getElementById("nav-forwards")!;
|
||||||
|
const reloadButton = document.getElementById("nav-reload")!;
|
||||||
|
const shareButton = document.getElementById("nav-share")!;
|
||||||
|
const preference = Alu.store.get("proxy").value;
|
||||||
if (preference === "ultraviolet") {
|
if (preference === "ultraviolet") {
|
||||||
iframe.src = window.__uv$config.prefix + window.__uv$config.encodeUrl(url);
|
iframe.src = window.__uv$config.prefix + window.__uv$config.encodeUrl(url);
|
||||||
} else if (preference == "rammerhead") {
|
} else if (preference == "rammerhead") {
|
||||||
// Check if rammerhead-session exists in cookies
|
// Check if rammerhead-session exists in cookies
|
||||||
let rammerheadSession = getCookie("rammerhead-session");
|
const rammerheadSession = getCookie("rammerhead-session");
|
||||||
console.log(rammerheadSession);
|
|
||||||
if (!rammerheadSession) {
|
if (!rammerheadSession) {
|
||||||
let session = await fetch("/newsession");
|
const session = await fetch("/newsession");
|
||||||
let sessionID = await session.text();
|
const sessionID = await session.text();
|
||||||
|
// Disable URL shuffling on rewrite, eventually I'll try and figure out how it works, but for now, it's disabled.
|
||||||
|
await fetch("/editsession?id=" + sessionID + "&enableShuffling=0");
|
||||||
// Now save it in a cookie that expires in 72 hours.
|
// Now save it in a cookie that expires in 72 hours.
|
||||||
document.cookie = `rammerhead-session=${sessionID}; max-age=${60 * 60 * 72}; path=/`;
|
document.cookie = `rammerhead-session=${sessionID}; max-age=${60 * 60 * 72}; path=/`;
|
||||||
|
// Now add an origin_proxy cookie for our domain
|
||||||
|
document.cookie = `origin_proxy=${window.location.origin}; max-age=${60 * 60 * 72}; path=/`;
|
||||||
}
|
}
|
||||||
iframe.src = `/${getCookie("rammerhead-session")}/${url}`;
|
if (iframe) iframe.src = `/${getCookie("rammerhead-session")}/${url}`;
|
||||||
} else {
|
} else {
|
||||||
// Default to UV
|
// Default to UV
|
||||||
iframe.src = window.__uv$config.prefix + window.__uv$config.encodeUrl(url);
|
iframe.src = window.__uv$config.prefix + window.__uv$config.encodeUrl(url);
|
||||||
|
|
@ -47,90 +114,123 @@
|
||||||
iframe.style.pointerEvents = "auto";
|
iframe.style.pointerEvents = "auto";
|
||||||
iframe.classList.add("proxy-frame");
|
iframe.classList.add("proxy-frame");
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
iframe.addEventListener("load", () => {
|
setTimeout(() => {
|
||||||
let topBar = document.getElementById("top-bar");
|
iframeLoad();
|
||||||
loadingContent.style.opacity = 0;
|
}, 500);
|
||||||
topBar.innerHTML = "";
|
|
||||||
topBar.classList.add("top-bar");
|
function setActive() {
|
||||||
let closeButton = document.createElement("button");
|
iframe.classList.add("active");
|
||||||
closeButton.classList.add("close-button");
|
|
||||||
closeButton.innerText = "Close";
|
|
||||||
closeButton.addEventListener("click", () => {
|
|
||||||
iframe.style.opacity = 0;
|
|
||||||
topBar.style.opacity = 0;
|
|
||||||
iframe.style.pointerEvents = "none";
|
|
||||||
topBar.style.pointerEvents = "none";
|
|
||||||
});
|
|
||||||
let urlText = document.createElement("p");
|
|
||||||
urlText.classList.add("url-text");
|
|
||||||
urlText.innerText = window.__uv$config.decodeUrl(iframe.src.split(__uv$config.prefix)[1]);
|
|
||||||
iframe.style.opacity = 1;
|
|
||||||
topBar.style.opacity = 1;
|
|
||||||
topBar.style.pointerEvents = "auto";
|
|
||||||
topBar.appendChild(closeButton);
|
|
||||||
topBar.appendChild(urlText);
|
|
||||||
document.body.appendChild(topBar);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function iframeLoad() {
|
||||||
|
loadingContent.style.opacity = "0";
|
||||||
|
iframe.style.opacity = "1";
|
||||||
|
topbar.style.opacity = "1";
|
||||||
|
topbar.style.pointerEvents = "auto";
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
iframe.addEventListener("load", setActive);
|
||||||
|
closeButton.onclick = () => {
|
||||||
|
iframe.style.opacity = "0";
|
||||||
|
topbar.style.opacity = "0";
|
||||||
|
iframe.style.pointerEvents = "none";
|
||||||
|
topbar.style.pointerEvents = "none";
|
||||||
|
document.body.style.overflow = "auto";
|
||||||
|
iframe.classList.remove("active");
|
||||||
|
iframe.removeEventListener("load", setActive);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
iframe.src = "about:blank";
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
forwardsButton.onclick = () => {
|
||||||
|
if (iframe.contentWindow) {
|
||||||
|
iframe.contentWindow.history.forward();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
backwardsButton.onclick = () => {
|
||||||
|
if (iframe.contentWindow) {
|
||||||
|
iframe.contentWindow.history.back();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reloadButton.onclick = () => {
|
||||||
|
if (iframe.contentWindow) {
|
||||||
|
iframe.contentWindow.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
shareButton.onclick = () => {
|
||||||
|
const proxyFrame = document.getElementById("proxy-frame") as HTMLIFrameElement;
|
||||||
|
if (proxy.value === "rammerhead") {
|
||||||
|
navigator.clipboard.writeText(window.location.origin + "/" + getCookie("rammerhead-session") + "/" + input!.value.trim());
|
||||||
|
} else {
|
||||||
|
navigator.clipboard.writeText(getUVProxyURL(proxyFrame));
|
||||||
|
}
|
||||||
|
new Notyf({
|
||||||
|
duration: 2000,
|
||||||
|
position: { x: "right", y: "bottom" },
|
||||||
|
dismissible: true,
|
||||||
|
ripple: true,
|
||||||
|
}).success("Copied URL to clipboard!");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function formEventListener(event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
await TransportMgr.updateTransport();
|
||||||
|
loadProxyContent();
|
||||||
|
}
|
||||||
|
window.loadFormContent = loadProxyContent;
|
||||||
|
|
||||||
function isUrl(val = "") {
|
function isUrl(val = "") {
|
||||||
if (/^http(s?):\/\//.test(val) || (val.includes(".") && val.substr(0, 1) !== " ")) return true;
|
if (/^http(s?):\/\//.test(val) || (val.includes(".") && val.substr(0, 1) !== " ")) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCookie(name) {
|
function getCookie(name: string) {
|
||||||
const value = `; ${document.cookie}`;
|
const value = `; ${document.cookie}`;
|
||||||
const parts = value.split(`; ${name}=`);
|
const parts = value.split(`; ${name}=`);
|
||||||
if (parts.length === 2) return parts.pop().split(";").shift();
|
if (parts.length === 2 && parts) {
|
||||||
|
const lastPart = parts.pop();
|
||||||
|
if (lastPart) {
|
||||||
|
return lastPart.split(";").shift();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSearchEngine() {
|
function getSearchEngine() {
|
||||||
let localStorageSearchEngine = localStorage.getItem("alu__search_engine");
|
return Alu.store.get("search").value;
|
||||||
if (!localStorageSearchEngine) {
|
|
||||||
return "https://google.com/search?q=";
|
|
||||||
}
|
|
||||||
switch (JSON.parse(localStorage.getItem("alu__search_engine")).value.toLowerCase()) {
|
|
||||||
case "google": {
|
|
||||||
return "https://google.com/search?q=";
|
|
||||||
}
|
|
||||||
case "bing": {
|
|
||||||
return "https://bing.com/search?q=d";
|
|
||||||
}
|
|
||||||
case "brave": {
|
|
||||||
return "https://search.brave.com/search?q=";
|
|
||||||
}
|
|
||||||
case "searx": {
|
|
||||||
let localStorageURL = localStorage.getItem("alu__searxngUrl");
|
|
||||||
if (localStorageURL) {
|
|
||||||
if (localStorageURL == "") return "https://searxng.site/search?q=";
|
|
||||||
// Ugly hack to remove the trailing slash :)
|
|
||||||
if (localStorageURL.endsWith("/")) localStorageURL = localStorageURL.slice(0, -1);
|
|
||||||
return localStorageURL + "/search?q=";
|
|
||||||
} else return "https://searxng.site/search?q=";
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return "https://google.com/search?q=";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProxyPreference() {
|
function updateProxiedFavicon(iframe: HTMLIFrameElement) {
|
||||||
let localStorageItem = localStorage.getItem("alu__selectedProxy");
|
const proxiedFavicon = document.getElementById("proxied-favicon") as HTMLImageElement;
|
||||||
|
if (iframe) {
|
||||||
if (!localStorageItem) return "uv";
|
if (iframe.contentDocument) {
|
||||||
|
const favicon = (iframe.contentDocument.querySelector("link[rel='icon']") as HTMLLinkElement) || (iframe.contentDocument.querySelector("link[rel*='icon']") as HTMLLinkElement);
|
||||||
switch (JSON.parse(localStorageItem).value.toLowerCase()) {
|
if (favicon && favicon.href.includes("data:image")) {
|
||||||
case "ultraviolet": {
|
proxiedFavicon.src = favicon.href;
|
||||||
return "ultraviolet";
|
return;
|
||||||
}
|
}
|
||||||
case "rammerhead":
|
const UVURL = getUVProxyURL(iframe);
|
||||||
return "rammerhead";
|
if (proxiedFavicon.src == `${window.location.origin}/custom-favicon?url=${UVURL}`) return;
|
||||||
case "dynamic":
|
proxiedFavicon.src = `/custom-favicon?url=${UVURL}`;
|
||||||
// temporary because dynamic is not implemented yet :)
|
|
||||||
return "ultraviolet";
|
|
||||||
default: {
|
|
||||||
return "uv";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function updateTopbarTitle(iframe: HTMLIFrameElement) {
|
||||||
|
if (!iframe.contentDocument) return;
|
||||||
|
const topbarTitle = document.getElementById("url-text") as HTMLElement;
|
||||||
|
if (iframe.contentDocument.title == "") {
|
||||||
|
topbarTitle.innerText = "Loading...";
|
||||||
|
} else {
|
||||||
|
if (iframe.contentDocument.title.length > 65) {
|
||||||
|
topbarTitle.innerText = iframe.contentDocument.title.slice(0, 65) + "...";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
topbarTitle.innerText = iframe.contentDocument.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
12
src/components/SchemaData.astro
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "Alu",
|
||||||
|
"url": "https://aluu.xyz",
|
||||||
|
"accessMode": "visual",
|
||||||
|
"acquireLicensePage": "https://github.com/titaniumnetwork-dev/Alu/blob/main/LICENSE",
|
||||||
|
"description": "Alu is a sleek web proxy supporting multiple standards of communication, and wide levels of customization. Similar to other proxies such as Holy Unblocker, Alu allows you to access blocked content while maintaining your privacy.",
|
||||||
|
"keywords": "web proxy, unblocker, alu, alu proxy, privacy, customization, wisp protocol, holy unblocker, titanium network, definitely science, kazwire, radon games, nebula, nebula proxy, censorship, bypass censorship, anura"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -1,33 +1,48 @@
|
||||||
---
|
---
|
||||||
import Input from "../Input.astro";
|
import Input from "@components/UI/Input.astro";
|
||||||
|
import { i18n } from "@i18n/utils";
|
||||||
|
const t = i18n.inferLangUseTranslations(Astro.url);
|
||||||
|
|
||||||
const presetCloaks = [
|
const presetCloaks = [
|
||||||
{ cloakTitle: "None", favicon: "/favicon.png" },
|
|
||||||
{
|
{
|
||||||
cloakTitle: "Google",
|
cloakTitle: "None",
|
||||||
favicon:
|
favicon: "/favicon.svg",
|
||||||
"https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://google.com&size=128",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cloakTitle: "Instructure",
|
cloakTitle: "Google",
|
||||||
favicon: "https://du11hjcvx0uqb.cloudfront.net/dist/images/favicon-e10d657a73.ico",
|
favicon: "/icons/google.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cloakTitle: "Canvas",
|
||||||
|
favicon: "/icons/canvas.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cloakTitle: "Google Classroom",
|
cloakTitle: "Google Classroom",
|
||||||
favicon: "https://ssl.gstatic.com/classroom/ic_product_classroom_144.png",
|
favicon: "/icons/classroom.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cloakTitle: "Imagine Edgenuity",
|
||||||
|
favicon: "/icons/edgenuity.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cloakTitle: "Classlink",
|
cloakTitle: "Classlink",
|
||||||
favicon:
|
favicon: "/icons/classlink.png",
|
||||||
"https://cdn.classlink.com/production/launchpad/resources/images/favicon/favicon-32x32.png",
|
},
|
||||||
|
{
|
||||||
|
cloakTitle: "Clever",
|
||||||
|
favicon: "/icons/clever.jpg",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cloakTitle: "Google Drive",
|
cloakTitle: "Google Drive",
|
||||||
favicon: "https://ssl.gstatic.com/docs/doclist/images/drive_2022q3_32dp.png",
|
favicon: "/icons/drive.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cloakTitle: "Schoology",
|
cloakTitle: "Schoology",
|
||||||
favicon: "https://asset-cdn.schoology.com/sites/all/themes/schoology_theme/favicon.ico",
|
favicon: "/icons/schoology.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cloakTitle: "YouTube",
|
||||||
|
favicon: "/icons/youtube.png",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
@ -38,10 +53,7 @@ const presetCloaks = [
|
||||||
{
|
{
|
||||||
presetCloaks.map((cloak: any) => {
|
presetCloaks.map((cloak: any) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div class="cloak-item" data-cloak-name={cloak.cloakTitle} data-cloak-icon={cloak.favicon}>
|
||||||
class="cloak-item"
|
|
||||||
data-cloak-name={cloak.cloakTitle}
|
|
||||||
data-cloak-icon={cloak.favicon}>
|
|
||||||
<img class="cloak-image" src={cloak.favicon} alt={cloak.cloakTitle} />
|
<img class="cloak-image" src={cloak.favicon} alt={cloak.cloakTitle} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -51,7 +63,7 @@ const presetCloaks = [
|
||||||
<div class="cloak-custom-override">
|
<div class="cloak-custom-override">
|
||||||
<Input inputName="cloak-custom-name" placeholder="Custom Name" height="30px" />
|
<Input inputName="cloak-custom-name" placeholder="Custom Name" height="30px" />
|
||||||
<Input inputName="cloak-custom-favicon" placeholder="Custom Favicon" height="30px" />
|
<Input inputName="cloak-custom-favicon" placeholder="Custom Favicon" height="30px" />
|
||||||
<button id="cloak-custom-button">Update Cloak</button>
|
<button id="cloak-custom-button">{t("settings.cloaking.updateCloak")}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -67,6 +79,7 @@ const presetCloaks = [
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.cloak-item {
|
.cloak-item {
|
||||||
width: 75px;
|
width: 75px;
|
||||||
|
|
@ -85,6 +98,7 @@ const presetCloaks = [
|
||||||
.cloak-image {
|
.cloak-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cloak-custom-override {
|
.cloak-custom-override {
|
||||||
|
|
@ -101,6 +115,7 @@ const presetCloaks = [
|
||||||
border: 0;
|
border: 0;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
font-family: "Varela Round", sans-serif !important;
|
||||||
}
|
}
|
||||||
.cloak-custom-input {
|
.cloak-custom-input {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,35 @@
|
||||||
---
|
---
|
||||||
import { getLangFromUrl, useTranslations } from "../../i18n/utils";
|
import Card from "@components/UI/Card.astro";
|
||||||
const lang = getLangFromUrl(Astro.url);
|
import { i18n } from "@i18n/utils";
|
||||||
const t = useTranslations(lang);
|
const t = i18n.inferLangUseTranslations(Astro.url);
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="settings-container">
|
<div class="settings-container">
|
||||||
<div class="credits-container">
|
<div class="credits-container">
|
||||||
<p class="credit-item">
|
<Card title={t("ultraviolet")} href="https://titaniumnetwork.org"> Titanium Network </Card>
|
||||||
{t("ultraviolet")} - <a
|
<Card title={t("settings.credits.esTranslations")} href="https://github.com/builtbyvys/"> vys </Card>
|
||||||
target="_blank"
|
<Card title={t("settings.credits.frTranslations")} href="https://github.com/notboeing747"> notboeing747 </Card>
|
||||||
rel="noreferrer noopener"
|
<Card title={t("settings.credits.jpTranslations")} href="https://wearr.dev"> wearr </Card>
|
||||||
href="https://titaniumnetwork.org/">Titanium Network</a
|
<Card title={t("settings.credits.ptTranslations")}> kersosina_ </Card>
|
||||||
>
|
<Card title={t("settings.credits.ruTranslations")} href="https://3kh0.net"> Echo </Card>
|
||||||
</p>
|
<Card title={t("settings.credits.zhTranslations")} href="https://3kh0.net"> Echo </Card>
|
||||||
<p class="credit-item">
|
<Card title={t("settings.credits.catppuccin")} href="https://github.com/catppuccin/catppuccin"> Catppuccin </Card>
|
||||||
{t("settings.credits.japaneseTranslations")} - <a
|
<Card title="Wisp Server" href="https://github.com/MercuryWorkshop/wisp-server-node"> Mercury Workshop </Card>
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
href="https://wearr.dev">wearr</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
<p class="credit-item">
|
|
||||||
{t("settings.credits.mochaandmacchiatothemes")} - <a
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
href="https://github.com/catppuccin/catppuccin">Catppuccin</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
<p class="credit-item">
|
|
||||||
Rosé Pine Theme - <a
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
href="https://rosepinetheme.com/">Rosé Pine</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.credit-item {
|
.credits-container {
|
||||||
color: var(--text-color);
|
display: grid;
|
||||||
font-size: 18px;
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
width: 100%;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
.credit-item > a {
|
.credit-item {
|
||||||
color: var(--text-color);
|
font-size: 20px;
|
||||||
font-weight: bold;
|
margin: 10px 0 10px;
|
||||||
|
}
|
||||||
|
.credit-name {
|
||||||
|
min-width: 150px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,33 @@
|
||||||
---
|
---
|
||||||
import Dropdown from "../Dropdown.astro";
|
import Dropdown from "@components/UI/Dropdown.astro";
|
||||||
|
|
||||||
import { getLangFromUrl, useTranslations } from "../../i18n/utils";
|
import { i18n } from "@i18n/utils";
|
||||||
const lang = getLangFromUrl(Astro.url);
|
const t = i18n.inferLangUseTranslations(Astro.url);
|
||||||
const t = useTranslations(lang);
|
|
||||||
|
|
||||||
const themeList = [
|
const themeList = [
|
||||||
{ name: t("settings.customization.theme.Alu"), value: "alu" },
|
{ name: t("settings.customization.theme.Alu"), value: "alu" },
|
||||||
{ name: t("settings.customization.theme.Macchiato"), value: "macchiato" },
|
{ name: t("settings.customization.theme.Macchiato"), value: "macchiato" },
|
||||||
{ name: t("settings.customization.theme.Mocha"), value: "mocha" },
|
{ name: t("settings.customization.theme.Mocha"), value: "mocha" },
|
||||||
{ name: "Rosé Pine", value: "rose_pine" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const languageList = [
|
const languageList = [
|
||||||
{ name: "English", value: "en" },
|
{ name: "English", value: "en" },
|
||||||
|
{ name: "Español", value: "es" },
|
||||||
|
{ name: "Français", value: "fr" },
|
||||||
{ name: "日本語", value: "jp" },
|
{ name: "日本語", value: "jp" },
|
||||||
|
{ name: "Português", value: "pt" },
|
||||||
|
{ name: "Русский", value: "ru" },
|
||||||
|
{ name: "中文", value: "zh" },
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="settings-container">
|
<div class="settings-container">
|
||||||
<div class="setting__theme">
|
<div class="setting__theme">
|
||||||
<label class="setting-label">{t("settings.customization.theme")}</label>
|
<label for="dropdown__selected-theme" aria-label="Theme" class="setting-label">{t("settings.customization.theme")}</label>
|
||||||
<Dropdown buttonNameDefault="Alu" dropdownList={themeList} , id="dropdown__selected-theme" />
|
<Dropdown buttonNameDefault="Alu" localStorageKey="theme" dropdownList={themeList} id="dropdown__selected-theme" />
|
||||||
</div>
|
</div>
|
||||||
<div class="setting__language">
|
<div class="setting__language">
|
||||||
<label class="setting-label">{t("settings.customization.language")}</label>
|
<label for="dropdown__selected-language" aria-label="Language" class="setting-label">{t("settings.customization.language")}</label>
|
||||||
<Dropdown
|
<Dropdown buttonNameDefault="English" localStorageKey="lang" dropdownList={languageList} id="dropdown__selected-language" />
|
||||||
buttonNameDefault="English"
|
|
||||||
dropdownList={languageList}
|
|
||||||
,
|
|
||||||
id="dropdown__selected-language"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,32 @@
|
||||||
---
|
---
|
||||||
import Input from "../Input.astro";
|
import Input from "@components/UI/Input.astro";
|
||||||
import Dropdown from "../Dropdown.astro";
|
import Dropdown from "@components/UI/Dropdown.astro";
|
||||||
|
|
||||||
import { getLangFromUrl, useTranslations } from "../../i18n/utils";
|
import { i18n } from "@i18n/utils";
|
||||||
const lang = getLangFromUrl(Astro.url);
|
const t = i18n.inferLangUseTranslations(Astro.url);
|
||||||
const t = useTranslations(lang);
|
|
||||||
|
const getWSProtocol = () => {
|
||||||
|
if (Astro.url.protocol === "https:") {
|
||||||
|
return "wss://";
|
||||||
|
} else {
|
||||||
|
return "ws://";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const proxyList = [
|
const proxyList = [
|
||||||
{ name: t("settings.proxy.auto"), value: "auto" },
|
{ name: t("settings.proxy.auto"), value: "auto" },
|
||||||
{ name: t("ultraviolet"), value: "ultraviolet" },
|
{ name: t("ultraviolet"), value: "ultraviolet" },
|
||||||
{ name: "Rammerhead", value: "rammerhead" },
|
{ name: "Rammerhead", value: "rammerhead" },
|
||||||
{ name: "Dynamic", value: "dynamic" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const searchEngineList = [
|
const searchEngineList = [
|
||||||
{ name: "Google", value: "google" },
|
{ name: "Google", value: "https://google.com/search?q=" },
|
||||||
{ name: "Bing", value: "bing" },
|
{ name: "DuckDuckGo", value: "https://duckduckgo.com/?q=" },
|
||||||
{ name: "Brave", value: "brave" },
|
{ name: "Bing", value: "https://bing.com/search?q=" },
|
||||||
{ name: "Searx", value: "searx" },
|
{ name: "Brave", value: "https://search.brave.com/search?q=" },
|
||||||
|
// Ecosia for some reason doesn't work with the proxy, hopefully I'll be able to add it eventually.
|
||||||
|
// { name: "Ecosia", value: "https://ecosia.org/search?q=" },
|
||||||
|
{ name: "Searx", value: "https://searxng.site/?q=" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const openPageWith = [
|
const openPageWith = [
|
||||||
|
|
@ -25,42 +34,71 @@ const openPageWith = [
|
||||||
{ name: "About:Blank", value: "about:blank" },
|
{ name: "About:Blank", value: "about:blank" },
|
||||||
{ name: t("settings.proxy.openPageWith.newTab"), value: "newTab" },
|
{ name: t("settings.proxy.openPageWith.newTab"), value: "newTab" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const transportsList = [
|
||||||
|
{ name: "Epoxy", value: "/epoxy/index.mjs" },
|
||||||
|
{ name: "Libcurl", value: "/libcurl/index.mjs" },
|
||||||
|
{ name: "Bare", value: "/baremod/index.mjs" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const wispURLList = [
|
||||||
|
{ name: "Alu (US)", value: "wss://aluu.xyz/wisp/" },
|
||||||
|
{ name: "Anura (US)", value: "wss://anura.pro/" },
|
||||||
|
{ name: "Custom", value: getWSProtocol() + Astro.url.host + "/wisp/" },
|
||||||
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="settings-container">
|
<div class="settings-container">
|
||||||
<div class="setting__selected-proxy">
|
<div class="setting__selected-proxy">
|
||||||
<label class="setting-label">{t("settings.proxy.selectedProxy")}</label>
|
<label aria-label="Selected Proxy" for="dropdown__selected-proxy" class="setting-label">{t("settings.proxy.selectedProxy")}</label>
|
||||||
<Dropdown
|
<Dropdown buttonNameDefault="Ultraviolet" dropdownList={proxyList} localStorageKey="proxy" id="dropdown__selected-proxy" />
|
||||||
buttonNameDefault="Ultraviolet"
|
|
||||||
dropdownList={proxyList}
|
|
||||||
,
|
|
||||||
id="dropdown__selected-proxy"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="setting__search-engine">
|
<div class="setting__search-engine">
|
||||||
<label class="setting-label">{t("settings.proxy.searchEngine")}</label>
|
<label aria-label="Search Engine" for="dropdown__search-engine" class="setting-label">{t("settings.proxy.searchEngine")}</label>
|
||||||
<Dropdown
|
<Dropdown buttonNameDefault="Google" dropdownList={searchEngineList} localStorageKey="search" id="dropdown__search-engine" />
|
||||||
buttonNameDefault="Google"
|
|
||||||
dropdownList={searchEngineList}
|
|
||||||
,
|
|
||||||
id="dropdown__search-engine"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="setting__open_with">
|
<div class="setting__open_with">
|
||||||
<label class="setting-label">{t("settings.proxy.openPageWith")}</label>
|
<label aria-label="Open Page With" for="dropdown__open-with" class="setting-label">{t("settings.proxy.openPageWith")}</label>
|
||||||
<Dropdown
|
<Dropdown buttonNameDefault={t("settings.proxy.openPageWith.embed")} dropdownList={openPageWith} localStorageKey="openpage" id="dropdown__open-with" />
|
||||||
buttonNameDefault={t("settings.proxy.openPageWith.embed")}
|
|
||||||
dropdownList={openPageWith}
|
|
||||||
,
|
|
||||||
id="dropdown__open-with"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="setting__bare-url">
|
<div class="setting__wisp_url">
|
||||||
<label class="setting-label" for="bare-url-input">{t("settings.proxy.bareURL")}</label>
|
<label aria-label="Wisp URL" for="dropdown__wisp-url" for="dropdown__wisp-url" class="setting-label">{t("settings.proxy.wispURL")}</label>
|
||||||
<Input inputName="bare-url" height="50px" />
|
<Dropdown buttonNameDefault={wispURLList[0].value} dropdownList={wispURLList} localStorageKey="wisp" id="dropdown__wisp-url" />
|
||||||
|
</div>
|
||||||
|
<div class="setting__bare_url">
|
||||||
|
<label aria-label="Bare Server URL" for="bare-url-input" class="setting-label">{t("settings.proxy.bareURL")}</label>
|
||||||
|
<Input height="50px" inputName="bare-url" />
|
||||||
|
</div>
|
||||||
|
<div class="setting__transport">
|
||||||
|
<label aria-label="Wisp Transport" for="dropdown__transport" class="setting-label">{t("settings.proxy.transport")}</label>
|
||||||
|
<Dropdown buttonNameDefault="Epoxy" dropdownList={transportsList} localStorageKey="transport" id="dropdown__transport" />
|
||||||
|
</div>
|
||||||
|
<div class="setting__reset">
|
||||||
|
<button id="reset-button">Reset Settings</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting__searxng-url">
|
<div class="setting__wisp-url setting-hidden">
|
||||||
<label for="searxng-url-input" class="setting-label">{t("settings.proxy.searxngURL")}</label>
|
<label aria-label="Custom Wisp URL" for="wisp-url-input" class="setting-label">{t("settings.proxy.wispURL")}</label>
|
||||||
|
<Input height="50px" inputName="wisp-url" defaultTextContent={getWSProtocol() + Astro.url.host + "/wisp/"} />
|
||||||
|
</div>
|
||||||
|
<div class="setting__searxng-url setting-hidden">
|
||||||
|
<label aria-label="SearXNG URL" for="searxng-url-input" class="setting-label">{t("settings.proxy.searxngURL")}</label>
|
||||||
<Input height="50px" inputName="searxng-url" defaultTextContent="https://searxng.site/" />
|
<Input height="50px" inputName="searxng-url" defaultTextContent="https://searxng.site/" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.setting__reset {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
#reset-button {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
border: none;
|
||||||
|
color: var(--text-color);
|
||||||
|
border-radius: 1rem;
|
||||||
|
padding: 10px;
|
||||||
|
margin-top: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,481 +0,0 @@
|
||||||
---
|
|
||||||
import ProxyTab from "./SettingsContent/ProxyTab.astro";
|
|
||||||
import CustomizationTab from "./SettingsContent/CustomizationTab.astro";
|
|
||||||
|
|
||||||
import { getLangFromUrl, useTranslations } from "../i18n/utils";
|
|
||||||
import CloakingTab from "./SettingsContent/CloakingTab.astro";
|
|
||||||
import CreditsTab from "./SettingsContent/CreditsTab.astro";
|
|
||||||
const lang = getLangFromUrl(Astro.url);
|
|
||||||
const t = useTranslations(lang);
|
|
||||||
---
|
|
||||||
|
|
||||||
<div class="content-hidden">
|
|
||||||
<div id="content-setting-tab-proxy">
|
|
||||||
<h1 class="content-setting-header">{t("settings.proxy")}</h1>
|
|
||||||
<ProxyTab />
|
|
||||||
</div>
|
|
||||||
<div id="content-setting-tab-customization">
|
|
||||||
<h1 class="content-setting-header">{t("settings.customization")}</h1>
|
|
||||||
<CustomizationTab />
|
|
||||||
</div>
|
|
||||||
<div id="content-setting-tab-cloaking">
|
|
||||||
<h1 class="content-setting-header">{t("settings.cloaking")}</h1>
|
|
||||||
<p class="content-setting-subtext">{t("settings.cloaking.subtext")}</p>
|
|
||||||
<CloakingTab />
|
|
||||||
</div>
|
|
||||||
<div id="content-setting-tab-credits">
|
|
||||||
<h1 class="content-setting-header">{t("settings.credits")}</h1>
|
|
||||||
<CreditsTab />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="popup">
|
|
||||||
<div class="tabs">
|
|
||||||
<input type="radio" id="setting-tab-proxy" class="setting-tab" name="tab" checked="true" />
|
|
||||||
<label for="setting-tab-proxy">Proxy</label>
|
|
||||||
<input type="radio" id="setting-tab-customization" class="setting-tab" name="tab" />
|
|
||||||
<label for="setting-tab-customization">Customization</label>
|
|
||||||
<input type="radio" id="setting-tab-cloaking" class="setting-tab" name="tab" />
|
|
||||||
<label for="setting-tab-cloaking">Cloaking</label>
|
|
||||||
<input type="radio" id="setting-tab-credits" class="setting-tab" name="tab" />
|
|
||||||
<label for="setting-tab-credits">Credits</label>
|
|
||||||
<div class="marker">
|
|
||||||
<div id="top"></div>
|
|
||||||
<div id="bottom"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="current-content"></div>
|
|
||||||
</div>
|
|
||||||
<script is:inline>
|
|
||||||
document.addEventListener("astro:before-swap", () => {
|
|
||||||
window.currentlySelectedTab = "";
|
|
||||||
document.removeEventListener("setting-tabChange", determineListener);
|
|
||||||
});
|
|
||||||
window.currentlySelectedTab;
|
|
||||||
window.loadedContentStorage = {};
|
|
||||||
|
|
||||||
Array.from(document.getElementsByClassName("setting-tab")).forEach((tab) => {
|
|
||||||
let contentToLoad = document.getElementById("content-" + tab.id);
|
|
||||||
if (contentToLoad) {
|
|
||||||
window.loadedContentStorage[tab.id] = contentToLoad.innerHTML;
|
|
||||||
contentToLoad.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
tab.addEventListener("click", (event) => {
|
|
||||||
loadContent(event.target.id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function loadContent(tabID) {
|
|
||||||
if (window.currentlySelectedTab == tabID) return;
|
|
||||||
else window.currentlySelectedTab = tabID;
|
|
||||||
let currentContent = document.getElementById("current-content");
|
|
||||||
if (currentContent) {
|
|
||||||
currentContent.style.opacity = "0";
|
|
||||||
setTimeout(() => {
|
|
||||||
currentContent.innerHTML = window.loadedContentStorage[tabID];
|
|
||||||
currentContent.style.opacity = "1";
|
|
||||||
document.dispatchEvent(new CustomEvent("setting-tabChange", { detail: tabID }));
|
|
||||||
document.dispatchEvent(new CustomEvent("setting-tabLoad", { detail: tabID }));
|
|
||||||
}, 250);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addDropdownListener() {
|
|
||||||
let dropdown_toggles = document.getElementsByClassName("dropdown-toggle");
|
|
||||||
Array.from(dropdown_toggles).forEach((toggle) => {
|
|
||||||
toggle.addEventListener("click", () => {
|
|
||||||
let dropdown = document.getElementById(toggle.id + "-menu");
|
|
||||||
if (dropdown) {
|
|
||||||
if (dropdown.style.maxHeight == "0px" || dropdown.style.maxHeight == "") {
|
|
||||||
dropdown.style.maxHeight = dropdown.scrollHeight + "px";
|
|
||||||
toggle.style.borderRadius = "10px 10px 0 0";
|
|
||||||
} else {
|
|
||||||
dropdown.style.maxHeight = "0px";
|
|
||||||
setTimeout(() => {
|
|
||||||
toggle.style.borderRadius = "10px";
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function determineListener(event) {
|
|
||||||
if (event.detail == "setting-tab-proxy") {
|
|
||||||
addDropdownListener();
|
|
||||||
} else if (event.detail == "setting-tab-customization") {
|
|
||||||
addDropdownListener();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDropdown(dropdownID) {
|
|
||||||
let dropdown = document.getElementById(dropdownID);
|
|
||||||
if (dropdown) {
|
|
||||||
dropdown.style.maxHeight = "0px";
|
|
||||||
setTimeout(() => {
|
|
||||||
let dropdown_toggle = document.getElementById(dropdownID.replace("-menu", ""));
|
|
||||||
dropdown_toggle.style.borderRadius = "10px";
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLocalStorageValue(localStorageItem, dropdownID) {
|
|
||||||
// I was kinda dumb for not doing this earlier.
|
|
||||||
let dropdown = document.getElementById(dropdownID);
|
|
||||||
let dropdownMenu = document.getElementById(dropdownID + "-menu");
|
|
||||||
|
|
||||||
if (dropdown && dropdownMenu) {
|
|
||||||
// Now we find the child that matches localStorageItem.value.
|
|
||||||
let dropdownItem = Array.from(dropdownMenu.children).find((item) => {
|
|
||||||
return JSON.parse(localStorage.getItem(localStorageItem)).value == item.dataset.setting;
|
|
||||||
});
|
|
||||||
// Now set the inner text to the name in the dropdownItem.
|
|
||||||
return dropdownItem.innerText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function applySavedLocalStorage(localStorageItem, dropdownID) {
|
|
||||||
if (localStorage.getItem(localStorageItem)) {
|
|
||||||
let dropdown_toggle = document.getElementById(dropdownID);
|
|
||||||
if (dropdown_toggle) {
|
|
||||||
dropdown_toggle.innerText = getLocalStorageValue(localStorageItem, dropdownID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyDropdownEventListeners(item, dropdownID, localStorageItem, optionalCallback) {
|
|
||||||
Array.from(item.children).forEach((item) => {
|
|
||||||
item.addEventListener("click", () => {
|
|
||||||
let localStorageItemContent = {
|
|
||||||
name: item.innerText,
|
|
||||||
value: item.dataset.setting,
|
|
||||||
};
|
|
||||||
localStorage.setItem(localStorageItem, JSON.stringify(localStorageItemContent));
|
|
||||||
applySavedLocalStorage(localStorageItem, dropdownID);
|
|
||||||
closeDropdown(item.parentElement.id);
|
|
||||||
if (typeof optionalCallback == "function") {
|
|
||||||
optionalCallback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// Array.from(item.children).forEach((item) => {
|
|
||||||
// item.addEventListener('click', () => {
|
|
||||||
// localStorage.setItem(localStorageItem, item.dataset.setting)
|
|
||||||
// applySavedLocalStorage(localStorageItem, dropdownID)
|
|
||||||
// closeDropdown(item.parentElement.id);
|
|
||||||
|
|
||||||
// if (typeof optionalCallback == "function") {
|
|
||||||
// optionalCallback();
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyInputListeners(item, localStorageItem) {
|
|
||||||
item.addEventListener("input", () => {
|
|
||||||
localStorage.setItem(localStorageItem, item.value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("setting-tabChange", determineListener);
|
|
||||||
|
|
||||||
loadContent("setting-tab-proxy");
|
|
||||||
|
|
||||||
function setupCustomizationSettings() {
|
|
||||||
applySavedLocalStorage("alu__selectedTheme", "dropdown__selected-theme");
|
|
||||||
applySavedLocalStorage("alu__selectedLanguage", "dropdown__selected-language");
|
|
||||||
let themeDropdown = document.getElementById("dropdown__selected-theme-menu");
|
|
||||||
let languageDropdown = document.getElementById("dropdown__selected-language-menu");
|
|
||||||
applyDropdownEventListeners(
|
|
||||||
themeDropdown,
|
|
||||||
"dropdown__selected-theme",
|
|
||||||
"alu__selectedTheme",
|
|
||||||
changeTheme
|
|
||||||
);
|
|
||||||
applyDropdownEventListeners(
|
|
||||||
languageDropdown,
|
|
||||||
"dropdown__selected-language",
|
|
||||||
"alu__selectedLanguage",
|
|
||||||
navigateToNewLangaugePage
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupCloakingSettings() {
|
|
||||||
Array.from(document.getElementById("cloak-list").children).forEach((cloak) => {
|
|
||||||
cloak.addEventListener("click", () => {
|
|
||||||
let cloakName = cloak.dataset.cloakName;
|
|
||||||
let cloakIcon = cloak.dataset.cloakIcon;
|
|
||||||
|
|
||||||
let localStorageItem = {
|
|
||||||
name: cloakName,
|
|
||||||
icon: cloakIcon,
|
|
||||||
isCustom: false,
|
|
||||||
};
|
|
||||||
localStorage.setItem("alu__selectedCloak", JSON.stringify(localStorageItem));
|
|
||||||
|
|
||||||
if (cloakName == "None") {
|
|
||||||
localStorage.removeItem("alu__selectedCloak");
|
|
||||||
cloakName = "Settings | Alu";
|
|
||||||
cloakIcon = "/favicon.png";
|
|
||||||
}
|
|
||||||
let link = document.querySelector("link[rel~='icon']");
|
|
||||||
if (!link) {
|
|
||||||
link = document.createElement("link");
|
|
||||||
link.rel = "icon";
|
|
||||||
document.head.appendChild(link);
|
|
||||||
}
|
|
||||||
link.href = cloakIcon;
|
|
||||||
document.title = cloakName;
|
|
||||||
|
|
||||||
if (!cloak.classList.contains("selected")) {
|
|
||||||
Array.from(document.getElementById("cloak-list").children).forEach((cloak2) => {
|
|
||||||
cloak2.classList.remove("selected");
|
|
||||||
});
|
|
||||||
cloak.classList.add("selected");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let customNameInput = document.getElementById("cloak-custom-name-input");
|
|
||||||
let customFaviconInput = document.getElementById("cloak-custom-favicon-input");
|
|
||||||
if (localStorage.getItem("alu__selectedCloak")) {
|
|
||||||
let selectedCloak = JSON.parse(localStorage.getItem("alu__selectedCloak"));
|
|
||||||
if (selectedCloak.isCustom) {
|
|
||||||
customNameInput.value = selectedCloak.name;
|
|
||||||
customFaviconInput.value = selectedCloak.icon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById("cloak-custom-button").addEventListener("click", () => {
|
|
||||||
let cloakName = document.getElementById("cloak-custom-name-input").value;
|
|
||||||
let cloakIcon = document.getElementById("cloak-custom-favicon-input").value;
|
|
||||||
let localStorageItem = {
|
|
||||||
name: cloakName,
|
|
||||||
icon: cloakIcon,
|
|
||||||
isCustom: true,
|
|
||||||
};
|
|
||||||
localStorage.setItem("alu__selectedCloak", JSON.stringify(localStorageItem));
|
|
||||||
if (cloakName == "None") {
|
|
||||||
localStorage.removeItem("alu__selectedCloak");
|
|
||||||
cloakName = "Settings | Alu";
|
|
||||||
cloakIcon = "/favicon.png";
|
|
||||||
}
|
|
||||||
let link = document.querySelector("link[rel~='icon']");
|
|
||||||
if (!link) {
|
|
||||||
link = document.createElement("link");
|
|
||||||
link.rel = "icon";
|
|
||||||
document.head.appendChild(link);
|
|
||||||
}
|
|
||||||
link.href = cloakIcon;
|
|
||||||
document.title = cloakName;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeTheme() {
|
|
||||||
let theme = JSON.parse(localStorage.getItem("alu__selectedTheme")).value;
|
|
||||||
if (theme) {
|
|
||||||
document.documentElement.setAttribute("data-theme", theme.toLowerCase());
|
|
||||||
let footer = document.getElementById("footer");
|
|
||||||
if (footer) {
|
|
||||||
footer.dataset.theme = theme.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupSettings(event) {
|
|
||||||
if (event.detail == "setting-tab-proxy") {
|
|
||||||
applySavedLocalStorage("alu__selectedProxy", "dropdown__selected-proxy");
|
|
||||||
applySavedLocalStorage("alu__search_engine", "dropdown__search-engine");
|
|
||||||
applySavedLocalStorage("alu__selectedOpenWith", "dropdown__open-with");
|
|
||||||
let selectedProxyDropdown = document.getElementById("dropdown__selected-proxy-menu");
|
|
||||||
let searchEngineDropdown = document.getElementById("dropdown__search-engine-menu");
|
|
||||||
let openWithDropdown = document.getElementById("dropdown__open-with-menu");
|
|
||||||
let bareUrlInput = document.getElementById("bare-url-input");
|
|
||||||
let searxngUrlInput = document.getElementById("searxng-url-input");
|
|
||||||
let savedSearxngUrl = localStorage.getItem("alu__searxngUrl");
|
|
||||||
if (savedSearxngUrl != undefined) {
|
|
||||||
if (savedSearxngUrl == "") localStorage.setItem("alu__searxngUrl", "https://searxng.site/");
|
|
||||||
searxngUrlInput.value = localStorage.getItem("alu__searxngUrl");
|
|
||||||
}
|
|
||||||
// Proxy settings
|
|
||||||
applyInputListeners(bareUrlInput, "alu__bareUrl");
|
|
||||||
applyInputListeners(searxngUrlInput, "alu__searxngUrl");
|
|
||||||
applyDropdownEventListeners(
|
|
||||||
searchEngineDropdown,
|
|
||||||
"dropdown__search-engine",
|
|
||||||
"alu__search_engine",
|
|
||||||
checkSearxng
|
|
||||||
);
|
|
||||||
applyDropdownEventListeners(
|
|
||||||
selectedProxyDropdown,
|
|
||||||
"dropdown__selected-proxy",
|
|
||||||
"alu__selectedProxy"
|
|
||||||
);
|
|
||||||
applyDropdownEventListeners(openWithDropdown, "dropdown__open-with", "alu__selectedOpenWith");
|
|
||||||
if (localStorage.getItem("bareUrl")) {
|
|
||||||
bareUrlInput.value = localStorage.getItem("bareUrl");
|
|
||||||
} else {
|
|
||||||
bareUrlInput.value = "/bare/";
|
|
||||||
}
|
|
||||||
checkSearxng();
|
|
||||||
} else if (event.detail == "setting-tab-customization") {
|
|
||||||
setupCustomizationSettings();
|
|
||||||
} else if (event.detail == "setting-tab-cloaking") {
|
|
||||||
setupCloakingSettings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkSearxng() {
|
|
||||||
// This function checks if the "searxng" option was clicked, display an additional option if so.
|
|
||||||
if (localStorage.getItem("alu__search_engine")) {
|
|
||||||
if (JSON.parse(localStorage.getItem("alu__search_engine")).value.toLowerCase() == "searx") {
|
|
||||||
document.getElementsByClassName("setting__searxng-url")[0].style.opacity = "1";
|
|
||||||
} else {
|
|
||||||
document.getElementsByClassName("setting__searxng-url")[0].style.opacity = "0";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("setting-tabLoad", setupSettings);
|
|
||||||
|
|
||||||
function navigateToNewLangaugePage() {
|
|
||||||
let value = JSON.parse(localStorage.getItem("alu__selectedLanguage")).value;
|
|
||||||
let currentLanguage = window.location.pathname.split("/")[1];
|
|
||||||
// Do nothing.. because we're already on the page.
|
|
||||||
if (value == currentLanguage) return;
|
|
||||||
switch (value) {
|
|
||||||
case "en":
|
|
||||||
window.location.href = "/en/settings/";
|
|
||||||
break;
|
|
||||||
case "jp":
|
|
||||||
window.location.href = "/jp/settings/";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style is:global>
|
|
||||||
.content-hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#current-content {
|
|
||||||
transition: opacity 250ms ease-in-out;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
.settings-container {
|
|
||||||
display: flex;
|
|
||||||
gap: 20px;
|
|
||||||
position: relative;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
.content-setting-header {
|
|
||||||
color: var(--text-color);
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
.content-setting-subtext {
|
|
||||||
font-size: 20px;
|
|
||||||
color: var(--text-color-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting-label {
|
|
||||||
color: var(--text-color);
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 400;
|
|
||||||
/* annoying stuff with label elements. */
|
|
||||||
display: block;
|
|
||||||
opacity: 1;
|
|
||||||
margin-block: 1em;
|
|
||||||
margin-inline: 0;
|
|
||||||
user-select: none;
|
|
||||||
width: 100%;
|
|
||||||
cursor: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting__searxng-url {
|
|
||||||
margin-top: 10px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 250ms ease-in-out;
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 700;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #d8d8d8;
|
|
||||||
opacity: 0.6;
|
|
||||||
transition: opacity 0.4s ease-in-out;
|
|
||||||
display: block;
|
|
||||||
width: calc(100% - 48px);
|
|
||||||
text-align: right;
|
|
||||||
z-index: 100;
|
|
||||||
user-select: none;
|
|
||||||
text-align: start;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
input[type="radio"] {
|
|
||||||
display: none;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
label:hover,
|
|
||||||
input[type="radio"]:checked + label {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.popup {
|
|
||||||
width: 98%;
|
|
||||||
height: 80%;
|
|
||||||
margin: 0 auto;
|
|
||||||
min-height: 400px;
|
|
||||||
max-height: 400px;
|
|
||||||
border-radius: 48px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: var(--background-color);
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
align-self: center;
|
|
||||||
}
|
|
||||||
.tabs {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 240px;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
position: relative;
|
|
||||||
gap: 25px;
|
|
||||||
}
|
|
||||||
.marker {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 200%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
top: calc(-100%);
|
|
||||||
left: 0;
|
|
||||||
transition: transform 0.2s ease-in-out;
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
}
|
|
||||||
.marker #bottom,
|
|
||||||
.marker #top {
|
|
||||||
background-color: var(--background-highlight);
|
|
||||||
}
|
|
||||||
.marker #top {
|
|
||||||
height: calc(50%);
|
|
||||||
margin-bottom: auto;
|
|
||||||
border-radius: 0 0 32px 0;
|
|
||||||
}
|
|
||||||
.marker #bottom {
|
|
||||||
height: calc(50% - 72px);
|
|
||||||
border-radius: 0 32px 0 0;
|
|
||||||
}
|
|
||||||
#setting-tab-proxy:checked ~ .marker {
|
|
||||||
transform: translateY(0%);
|
|
||||||
}
|
|
||||||
#setting-tab-customization:checked ~ .marker {
|
|
||||||
transform: translateY(13.5%);
|
|
||||||
}
|
|
||||||
#setting-tab-cloaking:checked ~ .marker {
|
|
||||||
transform: translateY(27%);
|
|
||||||
}
|
|
||||||
#setting-tab-credits:checked ~ .marker {
|
|
||||||
transform: translateY(41%);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,192 +0,0 @@
|
||||||
---
|
|
||||||
const { inputID } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<label class="switch">
|
|
||||||
<input id={inputID} checked="" type="checkbox" />
|
|
||||||
<div class="slider">
|
|
||||||
<div class="circle">
|
|
||||||
<svg
|
|
||||||
class="cross"
|
|
||||||
xml:space="preserve"
|
|
||||||
style="enable-background:new 0 0 512 512"
|
|
||||||
viewBox="0 0 365.696 365.696"
|
|
||||||
y="0"
|
|
||||||
x="0"
|
|
||||||
height="6"
|
|
||||||
width="6"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g>
|
|
||||||
<path
|
|
||||||
data-original="#000000"
|
|
||||||
fill="currentColor"
|
|
||||||
d="M243.188 182.86 356.32 69.726c12.5-12.5 12.5-32.766 0-45.247L341.238 9.398c-12.504-12.503-32.77-12.503-45.25 0L182.86 122.528 69.727 9.374c-12.5-12.5-32.766-12.5-45.247 0L9.375 24.457c-12.5 12.504-12.5 32.77 0 45.25l113.152 113.152L9.398 295.99c-12.503 12.503-12.503 32.769 0 45.25L24.48 356.32c12.5 12.5 32.766 12.5 45.247 0l113.132-113.132L295.99 356.32c12.503 12.5 32.769 12.5 45.25 0l15.081-15.082c12.5-12.504 12.5-32.77 0-45.25zm0 0"
|
|
||||||
></path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
<svg
|
|
||||||
class="checkmark"
|
|
||||||
xml:space="preserve"
|
|
||||||
style="enable-background:new 0 0 512 512"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
y="0"
|
|
||||||
x="0"
|
|
||||||
height="10"
|
|
||||||
width="10"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g>
|
|
||||||
<path
|
|
||||||
class=""
|
|
||||||
data-original="#000000"
|
|
||||||
fill="currentColor"
|
|
||||||
d="M9.707 19.121a.997.997 0 0 1-1.414 0l-5.646-5.647a1.5 1.5 0 0 1 0-2.121l.707-.707a1.5 1.5 0 0 1 2.121 0L9 14.171l9.525-9.525a1.5 1.5 0 0 1 2.121 0l.707.707a1.5 1.5 0 0 1 0 2.121z"
|
|
||||||
></path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.switch {
|
|
||||||
--switch-width: 46px;
|
|
||||||
--switch-height: 24px;
|
|
||||||
--switch-bg: rgb(131, 131, 131);
|
|
||||||
--switch-checked-bg: rgb(0, 218, 80);
|
|
||||||
--switch-offset: calc((var(--switch-height) - var(--circle-diameter)) / 2);
|
|
||||||
--switch-transition: all 0.2s cubic-bezier(0.27, 0.2, 0.25, 1.51);
|
|
||||||
--circle-diameter: 18px;
|
|
||||||
--circle-bg: #fff;
|
|
||||||
--circle-shadow: 1px 1px 2px rgba(146, 146, 146, 0.45);
|
|
||||||
--circle-checked-shadow: -1px 1px 2px rgba(163, 163, 163, 0.45);
|
|
||||||
--circle-transition: var(--switch-transition);
|
|
||||||
--icon-transition: all 0.2s cubic-bezier(0.27, 0.2, 0.25, 1.51);
|
|
||||||
--icon-cross-color: var(--switch-bg);
|
|
||||||
--icon-cross-size: 6px;
|
|
||||||
--icon-checkmark-color: var(--switch-checked-bg);
|
|
||||||
--icon-checkmark-size: 10px;
|
|
||||||
--effect-width: calc(var(--circle-diameter) / 2);
|
|
||||||
--effect-height: calc(var(--effect-width) / 2 - 1px);
|
|
||||||
--effect-bg: var(--circle-bg);
|
|
||||||
--effect-border-radius: 1px;
|
|
||||||
--effect-transition: all 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch input {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch svg {
|
|
||||||
-webkit-transition: var(--icon-transition);
|
|
||||||
-o-transition: var(--icon-transition);
|
|
||||||
transition: var(--icon-transition);
|
|
||||||
position: absolute;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch .checkmark {
|
|
||||||
width: var(--icon-checkmark-size);
|
|
||||||
color: var(--icon-checkmark-color);
|
|
||||||
-webkit-transform: scale(0);
|
|
||||||
-ms-transform: scale(0);
|
|
||||||
transform: scale(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch .cross {
|
|
||||||
width: var(--icon-cross-size);
|
|
||||||
color: var(--icon-cross-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider {
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: var(--switch-width);
|
|
||||||
height: var(--switch-height);
|
|
||||||
background: var(--switch-bg);
|
|
||||||
border-radius: 999px;
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
-webkit-transition: var(--switch-transition);
|
|
||||||
-o-transition: var(--switch-transition);
|
|
||||||
transition: var(--switch-transition);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle {
|
|
||||||
width: var(--circle-diameter);
|
|
||||||
height: var(--circle-diameter);
|
|
||||||
background: var(--circle-bg);
|
|
||||||
border-radius: inherit;
|
|
||||||
-webkit-box-shadow: var(--circle-shadow);
|
|
||||||
box-shadow: var(--circle-shadow);
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
-webkit-box-pack: center;
|
|
||||||
-ms-flex-pack: center;
|
|
||||||
justify-content: center;
|
|
||||||
-webkit-transition: var(--circle-transition);
|
|
||||||
-o-transition: var(--circle-transition);
|
|
||||||
transition: var(--circle-transition);
|
|
||||||
z-index: 1;
|
|
||||||
position: absolute;
|
|
||||||
left: var(--switch-offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
width: var(--effect-width);
|
|
||||||
height: var(--effect-height);
|
|
||||||
left: calc(var(--switch-offset) + (var(--effect-width) / 2));
|
|
||||||
background: var(--effect-bg);
|
|
||||||
border-radius: var(--effect-border-radius);
|
|
||||||
-webkit-transition: var(--effect-transition);
|
|
||||||
-o-transition: var(--effect-transition);
|
|
||||||
transition: var(--effect-transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* actions */
|
|
||||||
|
|
||||||
.switch input:checked + .slider {
|
|
||||||
background: var(--switch-checked-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch input:checked + .slider .checkmark {
|
|
||||||
-webkit-transform: scale(1);
|
|
||||||
-ms-transform: scale(1);
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch input:checked + .slider .cross {
|
|
||||||
-webkit-transform: scale(0);
|
|
||||||
-ms-transform: scale(0);
|
|
||||||
transform: scale(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch input:checked + .slider::before {
|
|
||||||
left: calc(100% - var(--effect-width) - (var(--effect-width) / 2) - var(--switch-offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch input:checked + .slider .circle {
|
|
||||||
left: calc(100% - var(--circle-diameter) - var(--switch-offset));
|
|
||||||
-webkit-box-shadow: var(--circle-checked-shadow);
|
|
||||||
box-shadow: var(--circle-checked-shadow);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<script>
|
|
||||||
function switchTheme() {
|
|
||||||
let currentTheme = localStorage.getItem("alu__selectedTheme");
|
|
||||||
|
|
||||||
if (currentTheme) {
|
|
||||||
document.documentElement.setAttribute(
|
|
||||||
"data-theme",
|
|
||||||
JSON.parse(currentTheme).value.toLowerCase()
|
|
||||||
);
|
|
||||||
let footer = document.getElementById("footer");
|
|
||||||
if (footer) {
|
|
||||||
footer.dataset.theme = JSON.parse(currentTheme).value.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switchTheme();
|
|
||||||
|
|
||||||
document.addEventListener("astro:after-swap", switchTheme);
|
|
||||||
</script>
|
|
||||||
53
src/components/UI/Card.astro
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
import Link from "./Link.astro";
|
||||||
|
|
||||||
|
const { title, href } = Astro.props;
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
href?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ID = title.toLowerCase().replaceAll(" ", "-");
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
href ? (
|
||||||
|
<Link href={href} newTab>
|
||||||
|
<div class="card card-link" id={"card-" + ID}>
|
||||||
|
<h2 class="card-title">{title}</h2>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div class="card" id={"card-" + ID}>
|
||||||
|
<h2 class="card-title">{title}</h2>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 18px;
|
||||||
|
background-color: var(--background-highlight);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
min-height: 140px;
|
||||||
|
}
|
||||||
|
.card-link {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: 250ms ease-in-out;
|
||||||
|
}
|
||||||
|
.card-link:hover {
|
||||||
|
filter: brightness(0.9);
|
||||||
|
}
|
||||||
|
.card-title {
|
||||||
|
margin: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
---
|
---
|
||||||
const { buttonNameDefault, dropdownList, id } = Astro.props;
|
const { buttonNameDefault, dropdownList, id, localStorageKey } = Astro.props;
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
buttonNameDefault: string;
|
||||||
|
dropdownList: { name: string; value: string }[];
|
||||||
|
id: string;
|
||||||
|
localStorageKey: Alu.ValidStoreKeys;
|
||||||
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<button id={id} class="dropdown-toggle" type="button" data-toggle="dropdown">
|
<button data-local-storage-key={localStorageKey} id={id} class="dropdown-toggle" type="button" data-toggle="dropdown">
|
||||||
{buttonNameDefault}
|
{buttonNameDefault}
|
||||||
<span class="caret"></span></button
|
</button>
|
||||||
>
|
|
||||||
<ul class="dropdown-menu" id={id + "-menu"}>
|
<ul class="dropdown-menu" id={id + "-menu"}>
|
||||||
{
|
{
|
||||||
dropdownList.map((item: any) => {
|
dropdownList.map((item: any) => {
|
||||||
|
|
@ -19,7 +25,7 @@ const { buttonNameDefault, dropdownList, id } = Astro.props;
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style is:global>
|
||||||
.dropdown {
|
.dropdown {
|
||||||
box-shadow: 4px 6px 15px 0px var(--background-color);
|
box-shadow: 4px 6px 15px 0px var(--background-color);
|
||||||
border-bottom-left-radius: 10px;
|
border-bottom-left-radius: 10px;
|
||||||
|
|
@ -52,6 +58,7 @@ const { buttonNameDefault, dropdownList, id } = Astro.props;
|
||||||
background-color: var(--dropdown-background-color);
|
background-color: var(--dropdown-background-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
z-index: 5;
|
||||||
}
|
}
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
border-bottom: 1px solid var(--text-color-accent);
|
border-bottom: 1px solid var(--text-color-accent);
|
||||||
87
src/components/UI/Footer.astro
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
---
|
||||||
|
import { i18n } from "@i18n/utils";
|
||||||
|
import Link from "./Link.astro";
|
||||||
|
import WaveSVG from "../WaveSVG.astro";
|
||||||
|
const t = i18n.inferLangUseTranslations(Astro.url);
|
||||||
|
---
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div aria-hidden="true" class="wave-svg-container">
|
||||||
|
<WaveSVG />
|
||||||
|
</div>
|
||||||
|
<div class="footer-top">
|
||||||
|
<div class="footer-title">
|
||||||
|
<h2>{t("footer.brand")}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-madeby">
|
||||||
|
<Link href="https://wearr.dev" newTab>{t("footer.madeWithLove")}</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<div class="footer-left">
|
||||||
|
<div class="footer-links">
|
||||||
|
<Link href="https://discord.gg/unblock" newTab>Join the discord!</Link>
|
||||||
|
<Link href="https://titaniumnetwork.org" newTab>{t("footer.poweredBy")}</Link>
|
||||||
|
|
||||||
|
<div class="footer-copyright">
|
||||||
|
<p>© {t("footer.aluProject")} 2024</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-right">
|
||||||
|
<div class="footer-links">
|
||||||
|
<Link href="/privacy">Privacy</Link>
|
||||||
|
<Link href="/terms">Terms</Link>
|
||||||
|
<Link href="https://wearr.dev/contact" newTab>Contact</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wave-svg-container {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 300px;
|
||||||
|
filter: brightness(1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
color: var(--text-color);
|
||||||
|
position: relative;
|
||||||
|
padding-top: 275px;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
.footer-top,
|
||||||
|
.footer-bottom {
|
||||||
|
width: 90%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-title {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</footer>
|
||||||
84
src/components/UI/Header.astro
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
---
|
||||||
|
import { i18n } from "@i18n/utils";
|
||||||
|
const lang = i18n.getLangFromUrl(Astro.url);
|
||||||
|
const t = i18n.useTranslations(lang);
|
||||||
|
---
|
||||||
|
|
||||||
|
<nav class="top-header">
|
||||||
|
<div id="title-background" class="title-background">
|
||||||
|
<div class="left">
|
||||||
|
<a href={`/${lang}/`} class="header-item flex-item"><img class="nav-img" src="/favicon.svg" alt="Alu Logo" /><span>{t("nav.brand")}</span></a>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<a href={`/${lang}/donate/`} class="header-item">Donate</a>
|
||||||
|
<a href={`/${lang}/marketplace/`} class="header-item">Marketplace</a>
|
||||||
|
<a href={`/${lang}/games/`} class="header-item">{t("nav.games")}</a>
|
||||||
|
<a href={`/${lang}/settings/`} class="header-item">{t("nav.settings")}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.top-header {
|
||||||
|
display: flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: 250ms ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-background {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-inline: 2.5rem;
|
||||||
|
height: 4.25rem;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom-left-radius: 0.5rem;
|
||||||
|
border-bottom-right-radius: 0.5rem;
|
||||||
|
box-shadow: -2px 5px 10px 0 var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.title-background {
|
||||||
|
padding-inline: 0.5rem;
|
||||||
|
}
|
||||||
|
.right > a:first-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.left,
|
||||||
|
.right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-item {
|
||||||
|
color: var(--text-color);
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 22px;
|
||||||
|
transition: 250ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 470px) {
|
||||||
|
.header-item {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-item:hover {
|
||||||
|
color: var(--text-color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-img {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
34
src/components/UI/Input.astro
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
const { inputName, defaultTextContent, height, placeholder, className, defaultStyles = true, autocomplete = "on" } = Astro.props;
|
||||||
|
|
||||||
|
const styleList = className ? className.split(" ") : [];
|
||||||
|
|
||||||
|
if (defaultStyles) {
|
||||||
|
styleList.push("astro-input");
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
inputName: string;
|
||||||
|
defaultTextContent?: string;
|
||||||
|
height?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
className?: string;
|
||||||
|
defaultStyles?: boolean;
|
||||||
|
autocomplete?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputHeight = height;
|
||||||
|
if (!height) {
|
||||||
|
inputHeight = "3rem";
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<input
|
||||||
|
style={`height: ${inputHeight}; font-family: 'Varela Round', sans-serif !important;`}
|
||||||
|
id={inputName + "-input"}
|
||||||
|
placeholder={placeholder || ""}
|
||||||
|
value={defaultTextContent || ""}
|
||||||
|
type="text"
|
||||||
|
class={styleList.map((style) => style).join(" ")}
|
||||||
|
autocomplete={autocomplete}
|
||||||
|
/>
|
||||||
21
src/components/UI/Link.astro
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
interface LinkProps {
|
||||||
|
href: string;
|
||||||
|
newTab?: boolean;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { href, newTab } = Astro.props as LinkProps;
|
||||||
|
const target = newTab ? "_blank" : "_self";
|
||||||
|
const rel = newTab ? "noopener noreferrer" : "";
|
||||||
|
---
|
||||||
|
|
||||||
|
<a href={href} target={target} rel={rel}>
|
||||||
|
<slot />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
29
src/components/UI/MarketplaceIcon.astro
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
import Paintbrush from "@components/icons/paintbrush.astro";
|
||||||
|
import Scroll from "@components/icons/scroll.astro";
|
||||||
|
|
||||||
|
const { type } = Astro.props;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
type: ExtType;
|
||||||
|
};
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="marketplace-icon">
|
||||||
|
<abbr title={type === "theme" ? "Theme" : "Script"}>
|
||||||
|
{type === "theme" ? <Paintbrush class="icon" /> : <Scroll class="icon" />}
|
||||||
|
</abbr>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style is:global>
|
||||||
|
.marketplace-icon {
|
||||||
|
width: 32px;
|
||||||
|
filter: brightness(0.8);
|
||||||
|
align-self: flex-start;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mp-icon {
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||