Mods listing, new home page and fixes on the backend side

This commit is contained in:
Gu://em_ 2025-05-13 21:49:56 +02:00
parent 0294d7d0c0
commit a7cf958770
24 changed files with 317 additions and 106 deletions

View file

@ -11,16 +11,17 @@
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.5.2",
"packageManager": "pnpm@10.10.0",
"dependencies": {
"ajv": "^8.17.1",
"bcrypt": "^5.1.1",
"better-sqlite3": "^11.9.1",
"dompurify": "^3.2.4",
"better-sqlite3": "^11.10.0",
"cors": "^2.8.5",
"dompurify": "^3.2.5",
"express": "^5.1.0",
"jsdom": "^26.0.0",
"jsdom": "^26.1.0",
"jsonwebtoken": "^9.0.2",
"marked": "^15.0.7",
"marked": "^15.0.11",
"mysql": "^2.18.1"
},
"pnpm": {
@ -30,6 +31,6 @@
]
},
"devDependencies": {
"nodemon": "^3.1.9"
"nodemon": "^3.1.10"
}
}

View file

@ -15,35 +15,38 @@ importers:
specifier: ^5.1.1
version: 5.1.1
better-sqlite3:
specifier: ^11.9.1
version: 11.9.1
specifier: ^11.10.0
version: 11.10.0
cors:
specifier: ^2.8.5
version: 2.8.5
dompurify:
specifier: ^3.2.4
specifier: ^3.2.5
version: 3.2.5
express:
specifier: ^5.1.0
version: 5.1.0
jsdom:
specifier: ^26.0.0
specifier: ^26.1.0
version: 26.1.0
jsonwebtoken:
specifier: ^9.0.2
version: 9.0.2
marked:
specifier: ^15.0.7
version: 15.0.10
specifier: ^15.0.11
version: 15.0.11
mysql:
specifier: ^2.18.1
version: 2.18.1
devDependencies:
nodemon:
specifier: ^3.1.9
specifier: ^3.1.10
version: 3.1.10
packages:
'@asamuzakjp/css-color@3.1.4':
resolution: {integrity: sha512-SeuBV4rnjpFNjI8HSgKUwteuFdkHwkboq31HWzznuqgySQir+jSTczoWVVL4jvOjKjuH80fMDG0Fvg1Sb+OJsA==}
'@asamuzakjp/css-color@3.1.7':
resolution: {integrity: sha512-Ok5fYhtwdyJQmU1PpEv6Si7Y+A4cYb8yNM9oiIJC9TzXPMuN9fvdonKJqcnz9TbFqV6bQ8z0giRq0iaOpGZV2g==}
'@csstools/color-helpers@5.0.2':
resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
@ -124,8 +127,8 @@ packages:
resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==}
engines: {node: '>= 10.0.0'}
better-sqlite3@11.9.1:
resolution: {integrity: sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==}
better-sqlite3@11.10.0:
resolution: {integrity: sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==}
bignumber.js@9.0.0:
resolution: {integrity: sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==}
@ -209,6 +212,10 @@ packages:
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
cors@2.8.5:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'}
cssstyle@4.3.1:
resolution: {integrity: sha512-ZgW+Jgdd7i52AaLYCriF8Mxqft0gD/R9i9wi6RWBhs1pqdPEzPjym7rvRKi397WmQFf3SlyUsszhw+VVCbx79Q==}
engines: {node: '>=18'}
@ -477,8 +484,8 @@ packages:
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
engines: {node: '>=12', npm: '>=6'}
jwa@1.4.1:
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
jwa@1.4.2:
resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==}
jws@3.2.2:
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
@ -511,8 +518,8 @@ packages:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
marked@15.0.10:
resolution: {integrity: sha512-BXzsfFiR2UqXFKRwpugWuCYi9mWd1aX/Yns/X52xWfvfen9lnGEDbJw9ZEjjvLZVqntqT2gX45eYvqb2dIokDw==}
marked@15.0.11:
resolution: {integrity: sha512-1BEXAU2euRCG3xwgLVT1y0xbJEld1XOrmRJpUwRCcy7rxhSCwMrmEu9LXoPhHSCJG41V7YcQ2mjKRr5BA3ITIA==}
engines: {node: '>= 18'}
hasBin: true
@ -580,8 +587,8 @@ packages:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'}
node-abi@3.74.0:
resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==}
node-abi@3.75.0:
resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==}
engines: {node: '>=10'}
node-addon-api@5.1.0:
@ -733,8 +740,8 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
semver@7.7.1:
resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
semver@7.7.2:
resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
engines: {node: '>=10'}
hasBin: true
@ -908,8 +915,8 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
ws@8.18.1:
resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==}
ws@8.18.2:
resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@ -932,7 +939,7 @@ packages:
snapshots:
'@asamuzakjp/css-color@3.1.4':
'@asamuzakjp/css-color@3.1.7':
dependencies:
'@csstools/css-calc': 2.1.3(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
'@csstools/css-color-parser': 3.0.9(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
@ -969,7 +976,7 @@ snapshots:
nopt: 5.0.0
npmlog: 5.0.1
rimraf: 3.0.2
semver: 7.7.1
semver: 7.7.2
tar: 6.2.1
transitivePeerDependencies:
- encoding
@ -1026,7 +1033,7 @@ snapshots:
- encoding
- supports-color
better-sqlite3@11.9.1:
better-sqlite3@11.10.0:
dependencies:
bindings: 1.5.0
prebuild-install: 7.1.3
@ -1121,9 +1128,14 @@ snapshots:
core-util-is@1.0.3: {}
cors@2.8.5:
dependencies:
object-assign: 4.1.1
vary: 1.1.2
cssstyle@4.3.1:
dependencies:
'@asamuzakjp/css-color': 3.1.4
'@asamuzakjp/css-color': 3.1.7
rrweb-cssom: 0.8.0
data-urls@5.0.0:
@ -1410,7 +1422,7 @@ snapshots:
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.2.0
ws: 8.18.1
ws: 8.18.2
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
@ -1430,9 +1442,9 @@ snapshots:
lodash.isstring: 4.0.1
lodash.once: 4.1.1
ms: 2.1.3
semver: 7.7.1
semver: 7.7.2
jwa@1.4.1:
jwa@1.4.2:
dependencies:
buffer-equal-constant-time: 1.0.1
ecdsa-sig-formatter: 1.0.11
@ -1440,7 +1452,7 @@ snapshots:
jws@3.2.2:
dependencies:
jwa: 1.4.1
jwa: 1.4.2
safe-buffer: 5.2.1
lodash.includes@4.3.0: {}
@ -1463,7 +1475,7 @@ snapshots:
dependencies:
semver: 6.3.1
marked@15.0.10: {}
marked@15.0.11: {}
math-intrinsics@1.1.0: {}
@ -1513,9 +1525,9 @@ snapshots:
negotiator@1.0.0: {}
node-abi@3.74.0:
node-abi@3.75.0:
dependencies:
semver: 7.7.1
semver: 7.7.2
node-addon-api@5.1.0: {}
@ -1530,7 +1542,7 @@ snapshots:
ignore-by-default: 1.0.1
minimatch: 3.1.2
pstree.remy: 1.1.8
semver: 7.7.1
semver: 7.7.2
simple-update-notifier: 2.0.0
supports-color: 5.5.0
touch: 3.1.1
@ -1583,7 +1595,7 @@ snapshots:
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 2.0.0
node-abi: 3.74.0
node-abi: 3.75.0
pump: 3.0.2
rc: 1.2.8
simple-get: 4.0.1
@ -1676,7 +1688,7 @@ snapshots:
semver@6.3.1: {}
semver@7.7.1: {}
semver@7.7.2: {}
send@1.2.0:
dependencies:
@ -1747,7 +1759,7 @@ snapshots:
simple-update-notifier@2.0.0:
dependencies:
semver: 7.7.1
semver: 7.7.2
sqlstring@2.3.1: {}
@ -1875,7 +1887,7 @@ snapshots:
wrappy@1.0.2: {}
ws@8.18.1: {}
ws@8.18.2: {}
xml-name-validator@5.0.0: {}

View file

@ -2,6 +2,7 @@
const express = require("express");
const app = express();
var cors = require('cors')
const configManager = require("./src/utils/configManager");
const { connectDatabase, initDatabase } = require('./src/database/index');
@ -12,6 +13,9 @@ const config = configManager.loadConfig();
// --- Body parsing ---
app.use(express.json()); // Necessary to parse JSON bodies
// --- Cors ---
app.use(cors());
// Database connection
(async () => {

View file

@ -25,15 +25,15 @@ export function App() {
return (
<>
<NavBar></NavBar>
<Router>
<HomePage path="/home" />
<HomePage path="/" />
<ModsPage path="/mods" />
{/* <AboutPage path="/about" /> */}
<SettingsPage path="/settings" />
</Router>
<NavBar></NavBar>
{/* Here for nothing */}
{/* <Button onClick={() => setCount((count) => count + 1)} style={{position: 'absolute', bottom: '10px'}}>

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M480-336.92 338.46-478.46l28.31-28.77L460-414v-346h40v346l93.23-93.23 28.31 28.77L480-336.92ZM264.62-200q-27.62 0-46.12-18.5Q200-237 200-264.62v-96.92h40v96.92q0 9.24 7.69 16.93 7.69 7.69 16.93 7.69h430.76q9.24 0 16.93-7.69 7.69-7.69 7.69-16.93v-96.92h40v96.92q0 27.62-18.5 46.12Q723-200 695.38-200H264.62Z"/></svg>

After

Width:  |  Height:  |  Size: 431 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M480-328.46 309.23-499.23l42.16-43.38L450-444v-336h60v336l98.61-98.61 42.16 43.38L480-328.46ZM252.31-180Q222-180 201-201q-21-21-21-51.31v-108.46h60v108.46q0 4.62 3.85 8.46 3.84 3.85 8.46 3.85h455.38q4.62 0 8.46-3.85 3.85-3.84 3.85-8.46v-108.46h60v108.46Q780-222 759-201q-21 21-51.31 21H252.31Z"/></svg>

After

Width:  |  Height:  |  Size: 418 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M460-171.46v-297.08L200-619.08v283.23q0 6.16 3.08 11.54 3.07 5.39 9.23 9.23L460-171.46Zm40 0 247.69-143.62q6.16-3.84 9.23-9.23 3.08-5.38 3.08-11.54v-283.23L500-468.54v297.08Zm-20-331.46 257-148.54-244.69-141.62q-6.16-3.84-12.31-3.84t-12.31 3.84L223-651.46l257 148.54ZM192.31-279.69q-15.16-8.69-23.73-23.62-8.58-14.92-8.58-32.31v-288.76q0-17.39 8.58-32.31 8.57-14.93 23.73-23.62l255.38-147.15q15.16-8.69 32.31-8.69 17.15 0 32.31 8.69l255.38 147.15q15.16 8.69 23.73 23.62 8.58 14.92 8.58 32.31v288.76q0 17.39-8.58 32.31-8.57 14.93-23.73 23.62L512.31-132.54q-15.16 8.69-32.31 8.69-17.15 0-32.31-8.69L192.31-279.69ZM480-480Z"/></svg>

After

Width:  |  Height:  |  Size: 745 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="m387.69-100-15.23-121.85q-16.07-5.38-32.96-15.07-16.88-9.7-30.19-20.77L196.46-210l-92.3-160 97.61-73.77q-1.38-8.92-1.96-17.92-.58-9-.58-17.93 0-8.53.58-17.34t1.96-19.27L104.16-590l92.3-159.23 112.46 47.31q14.47-11.46 30.89-20.96t32.27-15.27L387.69-860h184.62l15.23 122.23q18 6.54 32.57 15.27 14.58 8.73 29.43 20.58l114-47.31L855.84-590l-99.15 74.92q2.15 9.69 2.35 18.12.19 8.42.19 16.96 0 8.15-.39 16.58-.38 8.42-2.76 19.27L854.46-370l-92.31 160-112.61-48.08q-14.85 11.85-30.31 20.96-15.46 9.12-31.69 14.89L572.31-100H387.69ZM440-160h78.62L533-267.15q30.62-8 55.96-22.73 25.35-14.74 48.89-37.89L737.23-286l39.39-68-86.77-65.38q5-15.54 6.8-30.47 1.81-14.92 1.81-30.15 0-15.62-1.81-30.15-1.8-14.54-6.8-29.7L777.38-606 738-674l-100.54 42.38q-20.08-21.46-48.11-37.92-28.04-16.46-56.73-23.31L520-800h-79.38l-13.24 106.77q-30.61 7.23-56.53 22.15-25.93 14.93-49.47 38.46L222-674l-39.38 68L269-541.62q-5 14.24-7 29.62t-2 32.38q0 15.62 2 30.62 2 15 6.62 29.62l-86 65.38L222-286l99-42q22.77 23.38 48.69 38.31 25.93 14.92 57.31 22.92L440-160Zm40.46-200q49.92 0 84.96-35.04 35.04-35.04 35.04-84.96 0-49.92-35.04-84.96Q530.38-600 480.46-600q-50.54 0-85.27 35.04T360.46-480q0 49.92 34.73 84.96Q429.92-360 480.46-360ZM480-480Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="m405.38-120-14.46-115.69q-19.15-5.77-41.42-18.16-22.27-12.38-37.88-26.53L204.92-235l-74.61-130 92.23-69.54q-1.77-10.84-2.92-22.34-1.16-11.5-1.16-22.35 0-10.08 1.16-21.19 1.15-11.12 2.92-25.04L130.31-595l74.61-128.46 105.93 44.61q17.92-14.92 38.77-26.92 20.84-12 40.53-18.54L405.38-840h149.24l14.46 116.46q23 8.08 40.65 18.54 17.65 10.46 36.35 26.15l109-44.61L829.69-595l-95.31 71.85q3.31 12.38 3.7 22.73.38 10.34.38 20.42 0 9.31-.77 19.65-.77 10.35-3.54 25.04L827.92-365l-74.61 130-107.23-46.15q-18.7 15.69-37.62 26.92-18.92 11.23-39.38 17.77L554.62-120H405.38ZM440-160h78.23L533-268.31q30.23-8 54.42-21.96 24.2-13.96 49.27-38.27L736.46-286l39.77-68-87.54-65.77q5-17.08 6.62-31.42 1.61-14.35 1.61-28.81 0-15.23-1.61-28.81-1.62-13.57-6.62-29.88L777.77-606 738-674l-102.08 42.77q-18.15-19.92-47.73-37.35-29.57-17.42-55.96-23.11L520-800h-79.77l-12.46 107.54q-30.23 6.46-55.58 20.81-25.34 14.34-50.42 39.42L222-674l-39.77 68L269-541.23q-5 13.46-7 29.23t-2 32.77q0 15.23 2 30.23t6.23 29.23l-86 65.77L222-286l99-42q23.54 23.77 48.88 38.12 25.35 14.34 57.12 22.34L440-160Zm38.92-220q41.85 0 70.93-29.08 29.07-29.07 29.07-70.92t-29.07-70.92Q520.77-580 478.92-580q-42.07 0-71.04 29.08-28.96 29.07-28.96 70.92t28.96 70.92Q436.85-380 478.92-380ZM480-480Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -4,9 +4,9 @@
font-family: inherit;
font-weight: 500;
padding: 10px 15px;
padding: .4em .7em;
border: .1em;
border: .1rem;
border-style: solid;
border-radius: .3em;

View file

@ -1,19 +1,13 @@
import { h } from 'preact' // Necessary ?
import styles from './button.module.css'
function Button({ children, onClick, className, variant = 'primary', ...rest}) {
const buttonClasses = `${styles.button} ${styles[variant] || ''} ${className || ''}`
import styles from './grid.module.css'
function GridCard({item}) {
return (
<button
className={buttonClasses}
onClick= {onClick}
{...rest} // Allow passing other props like 'disabled', 'type', etc.
>
{children}
</button>
<div className={styles.gridCard}>
This is a card !
{item.name}
</div>
)
}
export default Button;
export default GridCard;

View file

@ -0,0 +1,9 @@
.gridCard {
background-color: #3a3a3a;
border: #4a4a4a .1em solid;
/* height: 10vh; */
/* width: 10vw; */
}

View file

@ -0,0 +1,31 @@
// Preact
import { h } from 'preact' // Necessary ?
// Components
import Button from '../Buttons/button'
// Styles
import styles from './row.module.css'
// Images
import Thumbnail from '../../assets/mod.svg'
import DownloadIcon from '../../assets/download_alt.svg'
function GridCard({item}) {
return (
<div className={styles.rowCard}>
<a href={'/mods/' + item.name}>
<img src={Thumbnail} className={styles.thumbnail}></img>
</a>
<p className={styles.description}> {item.description}
</p>
<div className={styles.titleDiv}>
<a className={styles.title}> {item.display_name}</a>
<a className={styles.author}> By {item.author}</a>
</div>
<Button href={"/mods/" + item.name} className={styles.downloadButton}>
<img src={DownloadIcon} className={styles.downloadIcon}></img>
Download
</Button>
</div>
)
}
export default GridCard;

View file

@ -0,0 +1,76 @@
.rowCard {
height: 7rem;
margin-bottom: 1rem;
background-color: #1a1a1a;
border: #3a3a3a .1rem solid;
border-radius: .5rem;
}
.thumbnail {
position: absolute;
/* top: 1rem; */
/* left: 1rem; */
margin: 0.93rem;
height: 5rem;
width: 5rem;
border: #3a3a3a .1rem solid;
border-radius: .5rem;
}
.titleDiv {
margin-left: 7rem;
margin-top: 1rem;
}
.title {
margin: 3rem 0;
font-size: 1.4rem;
font-weight: 600;
}
.author {
/* left: 17rem; */
/* margin: 1rem 0; */
color: #7a7a7a;
}
.description {
position: absolute;
left: 7rem;
margin: 3rem 0;
max-height: 10px;
color: #939393;
/*TODO limit height*/
}
.downloadButton {
position: absolute;
/* top: 1rem; */
right: 0;
margin: 0.8rem;
/* height: 5rem; */
/* width: 5rem; */
font-size: 1.1rem;
font-weight: 300;
border: #3a3a3a .1rem solid;
border-radius: .5rem;
}
.downloadIcon {
margin-bottom: -.35rem;
margin-right: .3rem;
}

View file

@ -16,7 +16,7 @@ function NavBar({ children, className, ...rest}) {
className={styles.navbar}
{...rest} // Allow passing other props like 'disabled', 'type', etc.
>
<a className={styles.leftItem} href='/home'> Home </a>
<a className={styles.leftItem} href='/'> Home </a>
<a className={styles.leftItem} href='/mods'> Mods </a>
<a className={styles.leftItem} href='/modpacks'> Modpacks </a>
<a className={styles.leftItem} href='/about'> About </a>

View file

@ -32,6 +32,8 @@
font-weight: 500;
transition: 200ms;
user-select: none;
}
.leftItem:hover {
@ -44,6 +46,8 @@
margin-right: 2em;
margin-top: .3em;
user-select: none;
transition: 200ms;
}

View file

@ -1,5 +1,4 @@
import { render } from 'preact'
import './styles/global.css'
import { App } from './app.jsx'
render(<App />, document.getElementById('app'))

View file

@ -3,6 +3,7 @@ import { h } from 'preact';
// Images
import logo from '../assets/logo.png'
import dl_icon from '../assets/download.svg'
// Styles
import '../styles/home.css'
@ -15,12 +16,12 @@ function HomePage() {
return (
<>
<a href="https://wf.oblic-parallels.fr" target="_blank">
<div href="https://wf.oblic-parallels.fr" target="_blank">
<img src={logo} class="logo img" alt="WF" />
<a class="logo text"> radio </a>
</a>
</div>
<div class='title'>An open place for mods</div>
<Button className='start-button'>Get started !</Button>
<Button className='start-button'>Get started</Button>
<div class='background'></div>
<div class='halo'></div>
</>

View file

@ -1,5 +1,9 @@
// Functions
// Preact
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
// Functions
import { fetchMods } from '../services/api';
// Components
import FiltersPanel from '../components/Filters/panel'
@ -9,19 +13,71 @@ import logo from '../assets/logo.png'
// Styles
import '../styles/mods.css'
import GridCard from '../components/Cards/grid';
import RowCard from '../components/Cards/row';
function ModsPage() {
return (
<>
<a href="https://wf.oblic-parallels.fr" target="_blank">
// UseState
const [mods, setMods] = useState([]);
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
// UseEffect
useEffect(() => {
async function loadItems() {
setLoading(true);
setError(false);
try {
const fetched_mods = await fetchMods();
setMods(fetched_mods);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
loadItems();
}, []); // <-- Tells useEffect to run once after render
if (loading) {
// TODO replace by loading screen
return <div>Loading mods</div>
}
if (error) {
// TODO replace by popup
return <div>Couldn't load mods: {error}</div>
}
// Debugging
console.debug(mods);
const testArray = [(1, 'a'), (2, 'b'), (3, 'c')];
return (
<>
<div href="https://wf.oblic-parallels.fr" target="_blank">
<img src={logo} class="logo img" alt="WF" />
<a class="logo text"> radio </a>
</a>
</div>
<FiltersPanel></FiltersPanel>
<div class='content-container'></div>
</>
<div class='content-container'>
{/* <GridCard>Test card</GridCard> */}
{/* <GridCard/> */}
{mods.map((mod) => {
console.debug(mod.name);
// return <div key={mod.name}>Test</div>
return <RowCard key={mod.name} item={mod}/>
})}
{testArray.map((item, index) => {
// <GridCard key={key}><GridCard/>
console.debug(index, item)
})}
</div>
</>
);
}

View file

@ -0,0 +1,15 @@
const API_BASE_URL = 'http://localhost:8000';
export async function fetchMods() {
try {
const response = await fetch(`${API_BASE_URL}/list/mods`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Failed to fetch items:', error);
return [];
}
}

View file

@ -1,3 +1,28 @@
/* Impports */
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
:root {
font-family: 'IBM Plex Mono';
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #0c0c0c;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
min-width: 320px;
margin: 0;
}
a {
text-decoration: none;
}
@ -9,22 +34,26 @@ a {
top: 1.6rem;
left: 2rem;
height: 6em;
padding: 1.5em;
user-select: none;
}
.logo.text {
position: relative;
left: 5rem;
top: 3.3rem;
position: absolute;
left: 10rem;
top: 3.8rem;
margin: 0;
color: #eaeaea;
font-family: Inter;
font-weight: 600;
padding: 1.5em;
font-size: 3em;
user-select: none;
}
h1 {
@ -53,10 +82,10 @@ h1 {
min-height: 20rem;
min-width: 50rem;
background-color: #1a1a1a;
/* background-color: #1a1a1a; */
color: #eaeaea;
border: #3a3a3a solid;
/* border: #3a3a3a solid; */
border-width: .1em;
border-radius: .5rem;
}

View file

@ -1,22 +0,0 @@
/* Impports */
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
:root {
font-family: 'IBM Plex Mono';
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #0c0c0c;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
min-width: 320px;
}

View file

@ -34,7 +34,7 @@
.start-button {
position: fixed;
top: 38rem;
top: 48rem;
left: 50%;
transform: translate(-50%, -50%); /*Center (compensate size)*/
@ -42,5 +42,4 @@
text-align: center;
font-weight: 600;
font-size: 2rem;
letter-spacing: 0.1rem;
}