feat: 🎉 initial commit
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
|
||||
}
|
13
index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
50
package.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "@rypidev/rypi-scrapper",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/press-start-2p": "^4.5.11",
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"classnames": "^2.3.2",
|
||||
"fast-xml-parser": "4.1.3",
|
||||
"framer-motion": "^10.10.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-feather": "^2.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.2.2",
|
||||
"@types/node": "^18.7.10",
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@vitejs/plugin-react": "^3.0.0",
|
||||
"@walidoux/eslint-config": "1.0.3",
|
||||
"@walidoux/prettier-config": "1.0.2",
|
||||
"autoprefixer": "10.4.14",
|
||||
"eslint": "8.36.0",
|
||||
"postcss": "8.4.21",
|
||||
"prettier": "2.8.7",
|
||||
"prettier-plugin-tailwindcss": "0.2.6",
|
||||
"tailwindcss": "3.3.1",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^4.0.0"
|
||||
},
|
||||
"prettier": "@walidoux/prettier-config",
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"@walidoux/eslint-config"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"**/*.config.js",
|
||||
"**/*.config.ts"
|
||||
]
|
||||
}
|
||||
}
|
3363
pnpm-lock.yaml
generated
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
24
public/Logo.svg
Normal file
@ -0,0 +1,24 @@
|
||||
<svg width="135" height="75" viewBox="0 0 135 75" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g clip-path="url(#clip0_14_41)">
|
||||
<rect x="17" y="61" width="92" height="14" fill="url(#pattern0)"/>
|
||||
<rect x="106.166" y="-12" width="44.2825" height="47.5385" transform="rotate(27.5 106.166 -12)" fill="url(#pattern1)"/>
|
||||
<rect x="0.555054" y="16.0185" width="123.471" height="41.4509" fill="url(#pattern2)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_14_41" transform="matrix(0.00469484 0 0 0.0308518 0 -0.00905433)"/>
|
||||
</pattern>
|
||||
<pattern id="pattern1" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image1_14_41" transform="matrix(0.0210496 0 0 0.0196078 -0.00519013 0)"/>
|
||||
</pattern>
|
||||
<pattern id="pattern2" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image2_14_41" transform="matrix(0.0102041 0 0 0.0303951 0 -0.00151981)"/>
|
||||
</pattern>
|
||||
<clipPath id="clip0_14_41">
|
||||
<rect width="135" height="75" fill="white"/>
|
||||
</clipPath>
|
||||
<image id="image0_14_41" width="213" height="33" xlink:href="data:image/png;base64,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"/>
|
||||
<image id="image1_14_41" width="48" height="51" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAzCAMAAADmSHsbAAABGlBMVEUAAAAAAAAAAAD/zk7/z07Hhhb/4iT+qQ3Rcz7SdD6mZwD/5DD/z0+vZACCPxCAPhDTdj/SdD+3XSfRcz3TdT/7vIv/0E+2XCf/z03/56//6LDcqk6nZQD/z0urfCP/64ulZACAPxG3XCfSd0DRdD/TdUD/zk3/6K+0Xij7uounZwD8vIqmZQCDQBClZwD/0U2zXib/zkz7vIr9vIqlZQD/5677vYv/0EzRcj7/5q+mZgCnaAC3Xie2XyeCQRD8uouoZwDSdEDRdD60XieCQRG0XSe2XSf7uYqCQhLSdj+kZQCCQA//z0y3XSi3XCb8uoyBPxH/5rD8vIuAPhHTdECnZgD/0Ev/zk+zXSb/6LH/5a7/57CmZAD/57FeylhiAAAAAnRSTlMAmf9A5tgAAAJPSURBVHhe7dHVjtxAEIbRcTUZhxmWmZnCzMz0/q+R+tu2NO7synsZRWnLd99xdcmVv/L8P5Sda+dGG6N1pK9HkCutYaLoGoR0pPD5KNIQhkp7nfVWsKKy+yilIfjRplSQ0jox6FOBXbSiKwnh64nBBHvy7ZnQFQA3MhA5MHaeXZ7A3F7pxDapMaxR2z9Cs6ORCxAkBgJHJSqvyfPQO4BUNkFN5ajRe8Q5eYVlCBkm4GGX1rUPhx0IAIz5E+S9NkSN9tebt1ICQJcATvlN2CJvtB89tmTTrjA7O5rhYVNAoWaT5379Qc8S9Djop4CyIEG+dIY8qO81QbhHjPWnge2xA907CxaJgnqwvNZjkvUv3q8XQZL2RB9bDSIGy36wtrDWy/rq3u0TyvtcoF9s328sAviBHwJmfXWhigmVaYB+u+0vZyDcsXHWV5u1Jy5QEZ3UguCZvwSws8v9zIztXzF4XXtTAGS4p85bv73UajHYFTFxan9Zr8lgobZeBCoyCXVqQSNo3SAh4okAiAHGc7jS/B1nB4oiOqwG/t0t0RUTISUR9wD1+vx8tbm9WQQVj4POw425WMZ9yWc/jiVhBQZMxk8PXOB5dPBcCDmRckX2RcyEsl7ud1+GzpUgaHU1PFqRYqXfjWUfE4i4F1J2x+HqsQNAiAbvNsJTXAhEMJOC6dzGcEj5j3bJ8PxT+PkLSJbLrYvjb8gvBR7I94vwFCTNw8EP5JcDCFxs8BME+dHwl83d3iXnIMgHJXmBlOYucfJy4ublxM3LiZuXk8q/eX4DFpU/BKxEv6oAAAAASUVORK5CYII="/>
|
||||
<image id="image2_14_41" width="98" height="33" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGIAAAAhCAYAAAAiaX7MAAAAAXNSR0IArs4c6QAABVxJREFUaEPtms9vE0cUx98k+EfsSJVMewiKFJo6FNlInHJrztxoz1z6DxTBoaeqZ04cQOkdVap6L/9CcmpyJBGqUFpQSpAoFkS2wTaw6I0zm9m38+ONMwuO1L0EvLtv3vd95v3YtQUAQKvVSnZ2dqDdbsNwOIROpwODwQB6vR6eDj7q9Xp6T6/XE8RAEmxwwhtarRacAl0yPgIh1Go12NragtXVVej3+3B4eCj/IhDuoQcf76lUKoB21bG/v48LFgKBro1rLi0tyfVPiS4hkiTJBadztwaDRwlUmmLiv5dvn4VqtQrlcjndlbu7uymYpz9UWfbP3nyd3vPizlzOn+GTElRWZmH0+AyUlgWM9hJYXu9Dt9vN7aFp04Ub6KjqCJkRjUYDNjY24KSOLqy/hoPrc5kAX/mtne7K7e1tGRxTQF3gz/3yBmzgRv9WoLxShtF+CSrLZ2Cw9xZKiyP45s7nMO26Vu7Nynhg+RbNZjNRu/akIGgGIRj9EGLcLmKCePtsHsoXyjA6qMIXPz2C57eaUFp4A6u35tJsnFZdl36vqV4sxOLioixNf373H6tUuHauKSPwevx8bW0NNjc3CwFRuViDz77/J2X+6tfzcOnnd/L/06wrA6LRaEgQD671YWF9mdubLdftAEBbnju4vpeCRRA4COilqXHjS9ZaWTs+/8brv7z3Cr76cZyN06wrA6Jer0sQ3e4SJH89ZQUneTjMXTdz9XjUfX+/DjNXz+eAYK3HI0la8P7+8Q42LSouluXH4sI56Nz9GxCc6R68jvqDa8/PP5b3T5supVX3UfYINVJicDgglGgM/Djg9mcNdV7VaAXCB0NB8IEwQcDPZr5+mbL9mLo4G4yCSKemEBCmTFDBoBmh73KkjyVGB2GDoUNwgeBAUGv4NlgsXVwQ6DtmuhDpOM/PCJezx5THWUIPLggKQQby4VCWOb0s2SDg9Xo2cEDE1MUBofs++21fhYoHguOsDMJRuTLVfAymtgMypQODbINAbYVA8IGIrcsHgvoeBILrLKfLawt7azh3XR0gzQYXCK79EF0uEKYNxAYR6qwrI1CQvrD+3ok2VO66DgjOIYRr31dy1XmlywaC0c/spSnU2ZCdg1OpDQR3XVrKSDZYQXDtc/RwQDBLqRlEEc4aMkJWDiUmdDdlpjJtXD2CnNrWs61oXVSDCwIZLPIginb2KIDqOwonCJ8QNVWR3pOxrUAUpUvfYDoIju9aFmdBcJ9cQ9KWpi8BYc0KjhAMrgVCJiOK1GUCMYHvbhAmgxEgoAn9W7tcVnCFkHJntGsqebF0mXoEPjzS7KP9TJ23Tk2+h6YCIKQtwtUrGEIoBGtGxIZgK01Kj8132jMz04UCEctZw3MD/f5aZyszw9TwMhdpLxzJOEz3Sc5eLF36QrrGEN+9IGI666jfpuQyBs4GgQoxGMzYi6mLA8KVCYa+yZuaJilJjCbt3MGhQlwgTHX7JJos2tJs5vjuzYgYDlIbzMxIdzB9W2obPfXxz5cRsXVxX9eYfJcNLfu63j++xhLAgGEEYYOAfn0KECYA+qChbyIXBOq/sVnHCr4jM0xNOwfCBaEoEK5AW+JifJ3igxANBDr87o/jH5Bx4HGnHFtNd7xfcoL1fS1ra74eTblnIddTvCpHus2gJ2ubM0WCsD0JU1+KKE2ezWILh3H01i82fd9y6kCYRHyE0uR65nFOfPQkx//M62huqdHr6CT3kFccaa9T/9BtMkTIrLdNTfh5RB+dGWFai+t/YT8MDqivORCcfkOucYKYwJ4NrhfEpGt9ChDe1xyBYmLbC4Vw0o00/ll+oOj/Ly8oAh8A/keUfCzV468AAAAASUVORK5CYII="/>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 7.7 KiB |
BIN
public/icons/game.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
public/icons/picture.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
public/images/GameAssets.png
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
public/images/Gamedata.png
Normal file
After Width: | Height: | Size: 103 KiB |
4
src-tauri/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
3400
src-tauri/Cargo.lock
generated
Normal file
23
src-tauri/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "rypi-scrapper"
|
||||
version = "0.0.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "1.2", features = ["fs-create-dir", "fs-exists", "fs-read-dir", "fs-write-file", "http-all", "shell-all", "window-close", "window-maximize", "window-minimize", "window-unmaximize"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem
|
||||
# DO NOT REMOVE!!
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
3
src-tauri/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
BIN
src-tauri/icons/128x128.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/128x128@2x.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
src-tauri/icons/32x32.png
Normal file
After Width: | Height: | Size: 974 B |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
After Width: | Height: | Size: 903 B |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
BIN
src-tauri/icons/icon.ico
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
src-tauri/icons/icon.png
Normal file
After Width: | Height: | Size: 14 KiB |
8
src-tauri/src/main.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
78
src-tauri/tauri.conf.json
Normal file
@ -0,0 +1,78 @@
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn build",
|
||||
"devPath": "http://localhost:1420",
|
||||
"distDir": "../dist",
|
||||
"withGlobalTauri": false
|
||||
},
|
||||
"package": {
|
||||
"productName": "rypi-scrapper",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"window": {
|
||||
"close": true,
|
||||
"minimize": true,
|
||||
"maximize": true,
|
||||
"unmaximize": true
|
||||
},
|
||||
"os": {
|
||||
"all": false
|
||||
},
|
||||
"fs": {
|
||||
"createDir": true,
|
||||
"exists": true,
|
||||
"readDir": true,
|
||||
"writeFile": true,
|
||||
"scope": ["$DOWNLOAD/**/*"]
|
||||
},
|
||||
"shell": {
|
||||
"all": true,
|
||||
"execute": true,
|
||||
"sidecar": true,
|
||||
"open": true,
|
||||
"scope": [
|
||||
{
|
||||
"name": "download-habbo-downloader",
|
||||
"cmd": "npm",
|
||||
"args": ["install", "-g", "habbo-downloader"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"http": {
|
||||
"all": true,
|
||||
"request": true,
|
||||
"scope": ["https://www.habbo.*/*", "https://images.habbo.*/*"]
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "com.tauri.dev",
|
||||
"targets": "all"
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"decorations": false,
|
||||
"center": true,
|
||||
"resizable": true,
|
||||
"width": 800,
|
||||
"height": 500
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
53
src/App.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
import { Image, Window, Button, Downloader } from './components'
|
||||
import { fetchGameData } from './utils/fetchGameData'
|
||||
import {
|
||||
GameAssetsDownloader,
|
||||
GameDataDownloader
|
||||
} from './config/GameDownloader'
|
||||
|
||||
const Main: React.FC = () => {
|
||||
const [error, setError] = useState('')
|
||||
const [response, setResponse] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const callback = (message: string, error = false): void => {
|
||||
if (error) return setError(message)
|
||||
if (message === 'COMPLETED') setLoading(false)
|
||||
else setResponse(message)
|
||||
}
|
||||
|
||||
return (
|
||||
<Window>
|
||||
<span className='mb-20 text-white'>I would like to:</span>
|
||||
|
||||
<ul className='flex gap-x-8'>
|
||||
<Downloader content={GameDataDownloader}>
|
||||
<Image src='/images/Gamedata.png' className='w-[400px]' />
|
||||
|
||||
<Button
|
||||
value='Download Gamedata'
|
||||
icon={<Image src='/icons/game.png' size={22} />}
|
||||
className='download-button border-gamedata-secondary bg-gamedata-primary shadow-gamedata-primary/20'
|
||||
handler={async () => {
|
||||
return await fetchGameData('com', callback)
|
||||
}}
|
||||
/>
|
||||
</Downloader>
|
||||
|
||||
<Downloader content={GameAssetsDownloader}>
|
||||
<Image src='/images/GameAssets.png' className='w-[400px]' />
|
||||
|
||||
<Button
|
||||
value='Download GameAssets'
|
||||
icon={<Image src='/icons/picture.png' icon />}
|
||||
className='download-button border-gameAssets-secondary bg-gameAssets-primary shadow-gameAssets-primary/40'
|
||||
/>
|
||||
</Downloader>
|
||||
</ul>
|
||||
</Window>
|
||||
)
|
||||
}
|
||||
|
||||
export default Main
|
27
src/components/Button/Button.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
interface ButtonProps extends React.ComponentPropsWithoutRef<'button'> {
|
||||
icon: JSX.Element
|
||||
value: string
|
||||
className?: string
|
||||
handler?: () => void
|
||||
}
|
||||
|
||||
export const Button: React.FC<ButtonProps> = ({
|
||||
icon,
|
||||
value,
|
||||
className,
|
||||
handler
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
onClick={handler}
|
||||
className={classNames(
|
||||
className,
|
||||
'flex items-center justify-center gap-x-5'
|
||||
)}>
|
||||
{icon}
|
||||
<span className='uppercase'>{value}</span>
|
||||
</button>
|
||||
)
|
||||
}
|
1
src/components/Button/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Button'
|
68
src/components/Downloader/Downloader.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import classNames from 'classnames'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { useState } from 'react'
|
||||
|
||||
export interface IDownloaderContent {
|
||||
title: string
|
||||
features: string[]
|
||||
}
|
||||
|
||||
interface DownloaderProps {
|
||||
className?: string
|
||||
children: React.ReactNode
|
||||
content: IDownloaderContent
|
||||
}
|
||||
|
||||
export const Downloader: React.FC<DownloaderProps> = ({
|
||||
className,
|
||||
children,
|
||||
content
|
||||
}) => {
|
||||
const [activeContent, setActiveContent] = useState(false)
|
||||
|
||||
const handleActiveContent = (): void => {
|
||||
return setActiveContent(!activeContent)
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
className={classNames(
|
||||
className,
|
||||
'relative rounded-xl shadow-red-500 hover:shadow-2xl'
|
||||
)}
|
||||
onMouseEnter={handleActiveContent}
|
||||
onMouseLeave={handleActiveContent}>
|
||||
{children}
|
||||
|
||||
<AnimatePresence>
|
||||
{activeContent && (
|
||||
<motion.ul
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1, transition: { staggerChildren: 0.5 } }}
|
||||
exit={{ opacity: 0 }}
|
||||
className='pointer-events-none absolute left-0 top-0 flex h-full w-full flex-col items-center justify-center rounded-xl bg-black/70 pb-5 text-[12px] text-white'>
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
className='mb-3 text-[16px]'>
|
||||
{content.title}
|
||||
</motion.h1>
|
||||
|
||||
{content.features.map((feature) => {
|
||||
return (
|
||||
<motion.span
|
||||
initial={{ opacity: 0, y: 50, scale: 0.75 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
exit={{ opacity: 0, y: 50, scale: 0.75 }}
|
||||
key={feature}>
|
||||
{feature}
|
||||
</motion.span>
|
||||
)
|
||||
})}
|
||||
</motion.ul>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</li>
|
||||
)
|
||||
}
|
1
src/components/Downloader/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Downloader'
|
19
src/components/Image/Image.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
interface ImageProps extends React.ComponentPropsWithoutRef<'img'> {
|
||||
size?: number
|
||||
icon?: boolean
|
||||
}
|
||||
|
||||
export const Image: React.FC<ImageProps> = ({ size, icon, ...rest }) => {
|
||||
return (
|
||||
<img
|
||||
{...rest}
|
||||
draggable={false}
|
||||
style={{ imageRendering: Boolean(icon) ? 'pixelated' : 'unset' }}
|
||||
className={classNames(rest.className, 'select-none')}
|
||||
height={size ?? rest.height}
|
||||
width={size ?? rest.width}
|
||||
/>
|
||||
)
|
||||
}
|
1
src/components/Image/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Image'
|
38
src/components/TitleBar/TitleBar.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { Maximize, Minus, X } from 'react-feather'
|
||||
import { appWindow } from '@tauri-apps/api/window'
|
||||
|
||||
import { Image } from '../Image'
|
||||
|
||||
export const TitleBar: React.FC = () => {
|
||||
return (
|
||||
<nav className='flex h-[37.5px] items-center justify-between bg-[#1f1f1f] text-white'>
|
||||
<Image src='/Logo.svg' size={60} className='ml-3 p-1' />
|
||||
|
||||
<ul className='flex h-full'>
|
||||
<li
|
||||
onClick={async () => {
|
||||
return await appWindow.minimize()
|
||||
}}
|
||||
className='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-[#2a2a2a]'>
|
||||
<Minus />
|
||||
</li>
|
||||
<li
|
||||
onClick={async () => {
|
||||
return (await appWindow.isMaximized())
|
||||
? await appWindow.unmaximize()
|
||||
: await appWindow.maximize()
|
||||
}}
|
||||
className='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-[#2a2a2a]'>
|
||||
<Maximize size={20} />
|
||||
</li>
|
||||
<li
|
||||
onClick={async () => {
|
||||
return await appWindow.close()
|
||||
}}
|
||||
className='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-red-500'>
|
||||
<X />
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
1
src/components/TitleBar/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './TitleBar'
|
19
src/components/Window/Window.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { Fragment } from 'react'
|
||||
|
||||
import { TitleBar } from '../TitleBar/TitleBar'
|
||||
|
||||
interface WindowProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export const Window: React.FC<WindowProps> = ({ children }) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<TitleBar />
|
||||
|
||||
<main className='flex h-screen w-screen flex-col items-center justify-center overflow-hidden bg-[#242424] p-10'>
|
||||
{children}
|
||||
</main>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
1
src/components/Window/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Window'
|
4
src/components/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './Window'
|
||||
export * from './Image'
|
||||
export * from './Button'
|
||||
export * from './Downloader'
|
62
src/config/ENDPOINTS.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { getClient, ResponseType } from '@tauri-apps/api/http'
|
||||
|
||||
import type { DomainTypes, GameEndPointsTypes } from '../types'
|
||||
|
||||
const PROD_VERSION_REGEX = /(production-[^/]+)/im
|
||||
const STABLE_PROD_VERSION = 'PRODUCTION-202303282207-162719871'
|
||||
|
||||
export let PROD_VERSION: string | undefined
|
||||
|
||||
const HABBO_URL = (domain: DomainTypes): string => {
|
||||
return `https://www.habbo.${domain}`
|
||||
}
|
||||
|
||||
const HABBO_IMAGES = `https://images.habbo.com/gordon/${
|
||||
PROD_VERSION ?? STABLE_PROD_VERSION
|
||||
}`
|
||||
|
||||
export const client = await getClient()
|
||||
await client
|
||||
.get(`${HABBO_URL('com')}/gamedata/external_variables/0`, {
|
||||
responseType: ResponseType.Text
|
||||
})
|
||||
.then(({ data }) => {
|
||||
return (PROD_VERSION = (data as string).match(PROD_VERSION_REGEX)?.[0])
|
||||
})
|
||||
|
||||
export const GAME_ENDPOINTS: GameEndPointsTypes = (domain) => {
|
||||
return [
|
||||
{
|
||||
src: `${HABBO_URL(domain)}/gamedata/figuredata/0`,
|
||||
convert: 'XML',
|
||||
fileName: 'FigureData'
|
||||
}
|
||||
/* {
|
||||
src: `${HABBO_IMAGES}/figuremap.xml`,
|
||||
convert: 'XML',
|
||||
fileName: 'FigureMap'
|
||||
},
|
||||
{
|
||||
src: `${HABBO_URL(domain)}/gamedata/furnidata_json/0`,
|
||||
fileName: 'FurniData'
|
||||
},
|
||||
{
|
||||
src: `${HABBO_URL(domain)}/gamedata/productdata_json/0`,
|
||||
fileName: 'ProductData'
|
||||
},
|
||||
{
|
||||
src: `${HABBO_IMAGES}/effectmap.xml`,
|
||||
convert: 'XML',
|
||||
fileName: 'EffectMap'
|
||||
},
|
||||
{
|
||||
src: `${HABBO_URL(domain)}/gamedata/external_variables/0`,
|
||||
convert: 'TXT',
|
||||
fileName: 'ExternalTexts'
|
||||
} */
|
||||
]
|
||||
}
|
||||
|
||||
export const ASSETS_ENDPOINTS = (domain: DomainTypes): string[] => {
|
||||
return [`${HABBO_URL(domain)}/`]
|
||||
}
|
17
src/config/GameDownloader.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import type { IDownloaderContent } from '../components'
|
||||
|
||||
export const GameDataDownloader: IDownloaderContent = {
|
||||
title: 'Converts and bundles:',
|
||||
features: ['XML/TXT to minified JSON files', 'Converts SWF files to JSV']
|
||||
}
|
||||
|
||||
export const GameAssetsDownloader: IDownloaderContent = {
|
||||
title: 'Fetches PNG/JPEG:',
|
||||
features: [
|
||||
'Badges + Badgeparts',
|
||||
'Album + Recepetion images',
|
||||
'Catalogue + Furni icons',
|
||||
'Habbo Web Promo + Articles',
|
||||
'MP3 Sounds machine'
|
||||
]
|
||||
}
|
12
src/main.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
|
||||
import './styles.css'
|
||||
import '@fontsource/press-start-2p'
|
||||
import App from './App'
|
||||
|
||||
createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
)
|
3
src/mapping/convertTXT.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const convertTXT = (data: string) => {
|
||||
console.log(data)
|
||||
}
|
194
src/mapping/convertXML.ts
Normal file
@ -0,0 +1,194 @@
|
||||
import type {
|
||||
IEffectMap,
|
||||
IEffectMapLibrary,
|
||||
IFigureData,
|
||||
IFigureDataColor,
|
||||
IFigureDataHiddenLayer,
|
||||
IFigureDataPalette,
|
||||
IFigureDataPart,
|
||||
IFigureDataSet,
|
||||
IFigureDataSetType,
|
||||
IFigureMap,
|
||||
IFigureMapLibrary,
|
||||
IFigureMapLibraryPart
|
||||
} from '../types'
|
||||
|
||||
export const convertXML = (
|
||||
XML: any,
|
||||
url: string
|
||||
): IFigureData | IFigureMap | IEffectMap => {
|
||||
if (url.includes('figuredata')) {
|
||||
const output: IFigureData = { palettes: [], setTypes: [] }
|
||||
|
||||
for (const paletteXML of XML.figuredata.colors.palette) {
|
||||
const palette: IFigureDataPalette = { id: 0, color: [] }
|
||||
|
||||
if (paletteXML.id !== undefined) palette.id = paletteXML.id
|
||||
|
||||
if (paletteXML.color !== undefined) {
|
||||
for (const colorXML of paletteXML.color) {
|
||||
const color: IFigureDataColor = {
|
||||
id: 0,
|
||||
index: 0,
|
||||
club: 0,
|
||||
selectable: false,
|
||||
hexCode: ''
|
||||
}
|
||||
|
||||
const hexColor = String(colorXML['#text' as keyof IFigureDataColor])
|
||||
|
||||
if (colorXML.id !== undefined) color.id = colorXML.id
|
||||
if (colorXML.index !== undefined) color.index = colorXML.index
|
||||
if (colorXML.club !== undefined) color.club = colorXML.club
|
||||
if (colorXML.selectable !== undefined)
|
||||
color.selectable = colorXML.selectable === 0 ? true : false
|
||||
if (hexColor !== undefined) color.hexCode = hexColor
|
||||
|
||||
palette.color.push(color)
|
||||
}
|
||||
}
|
||||
|
||||
output.palettes.push(palette)
|
||||
}
|
||||
|
||||
for (const setTypeXML of XML.figuredata.sets.settype) {
|
||||
const settype: IFigureDataSetType = {
|
||||
type: '',
|
||||
paletteId: 0,
|
||||
mandatoryF0: false,
|
||||
mandatoryF1: false,
|
||||
mandatoryM0: false,
|
||||
mandatoryM1: false,
|
||||
sets: []
|
||||
}
|
||||
|
||||
if (setTypeXML.type !== undefined) settype.type = setTypeXML.type
|
||||
if (setTypeXML.paletteId !== undefined)
|
||||
settype.paletteId = setTypeXML.paletteId
|
||||
if (setTypeXML.mandatoryF0 !== undefined)
|
||||
settype.mandatoryF0 = setTypeXML.mandatoryF0
|
||||
if (setTypeXML.mandatoryF1 !== undefined)
|
||||
settype.mandatoryF1 = setTypeXML.mandatoryF1
|
||||
if (setTypeXML.mandatoryM0 !== undefined)
|
||||
settype.mandatoryM0 = setTypeXML.mandatoryM0
|
||||
if (setTypeXML.mandatoryM1 !== undefined)
|
||||
settype.mandatoryM1 = setTypeXML.mandatoryM1
|
||||
|
||||
if (setTypeXML.sets !== undefined) {
|
||||
for (const setXML of setTypeXML.sets) {
|
||||
const setType: IFigureDataSet = {
|
||||
id: 0,
|
||||
gender: 'U',
|
||||
club: 0,
|
||||
colorable: false,
|
||||
selectable: false,
|
||||
preselectable: false,
|
||||
sellable: false,
|
||||
parts: [],
|
||||
hiddenLayers: []
|
||||
}
|
||||
|
||||
if (setXML.id !== undefined) setType.id = setXML.id
|
||||
if (setXML.gender !== undefined) setType.gender = setXML.gender
|
||||
if (setXML.club !== undefined) setType.club = setXML.club
|
||||
if (setXML.colorable !== undefined)
|
||||
setType.colorable = setXML.colorable === 0 ? true : false
|
||||
if (setXML.selectable !== undefined)
|
||||
setType.selectable = setXML.selectable
|
||||
if (setXML.preselectable !== undefined)
|
||||
setType.preselectable = setXML.preselectable
|
||||
if (setXML.sellable !== undefined) setType.sellable = setXML.sellable
|
||||
|
||||
if (setXML.parts !== undefined) {
|
||||
for (const partXML of setXML.parts) {
|
||||
const part: IFigureDataPart = {
|
||||
id: 0,
|
||||
type: '',
|
||||
colorable: false,
|
||||
index: 0,
|
||||
colorindex: 0
|
||||
}
|
||||
|
||||
if (partXML.id !== undefined) part.id = partXML.id
|
||||
if (partXML.type !== undefined) part.type = partXML.type
|
||||
if (partXML.colorable !== undefined)
|
||||
part.colorable = partXML.colorable
|
||||
if (partXML.index !== undefined) part.index = partXML.index
|
||||
if (partXML.colorindex !== undefined)
|
||||
part.colorindex = partXML.colorindex
|
||||
|
||||
setType.parts.push(part)
|
||||
}
|
||||
}
|
||||
|
||||
if (setXML.hiddenLayers !== undefined) {
|
||||
for (const hiddenLayerXML of setXML.hiddenLayers) {
|
||||
const hiddenLayer: IFigureDataHiddenLayer = { partType: '' }
|
||||
|
||||
if (hiddenLayerXML.partType !== undefined)
|
||||
hiddenLayer.partType = hiddenLayerXML.partType
|
||||
|
||||
setType.hiddenLayers?.push(hiddenLayer)
|
||||
}
|
||||
}
|
||||
|
||||
settype.sets.push(setType)
|
||||
}
|
||||
}
|
||||
|
||||
output.setTypes.push(setTypeXML)
|
||||
}
|
||||
|
||||
return output
|
||||
} else if (url.includes('figuremap')) {
|
||||
const output: IFigureMap = { libraries: [] }
|
||||
|
||||
for (const libraryXML of XML.map.lib as IFigureMapLibrary[]) {
|
||||
const library: IFigureMapLibrary = { id: '', revision: 0, part: [] }
|
||||
|
||||
if (libraryXML.id !== undefined) library.id = libraryXML.id
|
||||
if (libraryXML.revision !== undefined)
|
||||
library.revision = libraryXML.revision
|
||||
|
||||
if (Array.isArray(libraryXML.part)) {
|
||||
for (const libraryPart of libraryXML.part) {
|
||||
const libraryPartXML: IFigureMapLibraryPart = { id: 0, type: '' }
|
||||
|
||||
if (libraryPart.id !== undefined) libraryPartXML.id = libraryPart.id
|
||||
if (libraryPart.type !== undefined)
|
||||
libraryPartXML.type = libraryPart.type
|
||||
|
||||
library.part.push(libraryPartXML)
|
||||
}
|
||||
} else {
|
||||
const libraryPart = libraryXML.part as unknown as IFigureMapLibraryPart
|
||||
library.part.push({ id: libraryPart.id, type: libraryPart.type })
|
||||
}
|
||||
|
||||
output.libraries.push(library)
|
||||
}
|
||||
|
||||
return output
|
||||
} else {
|
||||
const output: IEffectMap = { effects: [] }
|
||||
|
||||
for (const libraryXML of XML.map.effect as IEffectMapLibrary[]) {
|
||||
const library: IEffectMapLibrary = {
|
||||
id: 0,
|
||||
lib: '',
|
||||
type: '',
|
||||
revision: 0
|
||||
}
|
||||
|
||||
if (libraryXML.id !== undefined) library.id = libraryXML.id
|
||||
if (libraryXML.lib !== undefined) library.lib = libraryXML.lib
|
||||
if (libraryXML.type !== undefined) library.type = libraryXML.type
|
||||
if (libraryXML.revision !== undefined)
|
||||
library.revision = libraryXML.revision
|
||||
|
||||
output.effects.push(library)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
}
|
2
src/mapping/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './convertXML'
|
||||
export * from './convertTXT'
|
25
src/styles.css
Normal file
@ -0,0 +1,25 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
#root {
|
||||
font-family: 'Press Start 2P';
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.retro-text-shadow {
|
||||
text-shadow: 0px 1.5px 0px #000000, -1px 3px 0px rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
|
||||
.center-x-axis {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.download-button {
|
||||
@apply retro-text-shadow center-x-axis center-x-axis -bottom-4 z-10 h-12 w-10/12 border-2 text-xs text-white shadow-2xl transition-all hover:-translate-x-1/2 hover:scale-105 hover:duration-200 active:-translate-x-1/2 active:scale-95 active:opacity-80 active:shadow-none active:duration-75;
|
||||
}
|
||||
}
|
30
src/types/Converters.d.ts
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
import type {
|
||||
IEffectMapLibrary,
|
||||
IFigureDataPalette,
|
||||
IFigureDataSetType,
|
||||
IFigureMapLibrary,
|
||||
IFurni,
|
||||
IProduct
|
||||
} from './SubConverters'
|
||||
|
||||
export interface IFigureData {
|
||||
palettes: IFigureDataPalette[]
|
||||
setTypes: IFigureDataSetType[]
|
||||
}
|
||||
|
||||
export interface IFigureMap {
|
||||
libraries: IFigureMapLibrary[]
|
||||
}
|
||||
|
||||
export interface IFurniData {
|
||||
roomitemtypes: { furnitype: IFurni }
|
||||
wallitemtypes: { furnitype: IFurni }
|
||||
}
|
||||
|
||||
export interface IEffectMap {
|
||||
effects: IEffectMapLibrary[]
|
||||
}
|
||||
|
||||
export interface IProductData {
|
||||
productData: { product: IProduct }
|
||||
}
|
10
src/types/Domain.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
export type DomainTypes =
|
||||
| 'com.br'
|
||||
| 'com.tr'
|
||||
| 'com'
|
||||
| 'de'
|
||||
| 'es'
|
||||
| 'fi'
|
||||
| 'fr'
|
||||
| 'it'
|
||||
| 'nl'
|
3
src/types/Endpoint.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export type GameEndPointsTypes = (
|
||||
domain: DomainTypes
|
||||
) => Array<{ src: string; convert?: 'TXT' | 'XML'; fileName: string }>
|
98
src/types/SubConverters.d.ts
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
export interface IFurni {
|
||||
id: number
|
||||
classname: string
|
||||
revision: number
|
||||
category: string
|
||||
defaultdir: number
|
||||
xdim: number
|
||||
ydim: number
|
||||
partcolors: { color: string[] }
|
||||
name: string
|
||||
description: string
|
||||
adurl: string
|
||||
offerid: number
|
||||
buyout: boolean
|
||||
rentofferid: number
|
||||
rentbuyout: boolean
|
||||
bc: boolean
|
||||
excludeddynamic: boolean
|
||||
customparams: string
|
||||
specialtype: number
|
||||
canstandon: boolean
|
||||
cansiton: boolean
|
||||
canlayon: boolean
|
||||
furniline: string
|
||||
environment: string
|
||||
rare: boolean
|
||||
}
|
||||
|
||||
export interface IFigureDataColor {
|
||||
id: number
|
||||
index: number
|
||||
club: number // must be changed, either 0, 1, 2
|
||||
selectable: boolean
|
||||
hexCode: string
|
||||
}
|
||||
|
||||
export interface IFigureDataPalette {
|
||||
id: number
|
||||
color: IFigureDataColor[]
|
||||
}
|
||||
|
||||
export interface IFigureDataPart {
|
||||
id: number
|
||||
type: string // must be changed
|
||||
colorable: boolean // must be changed
|
||||
index: number
|
||||
colorindex: number
|
||||
}
|
||||
|
||||
export interface IFigureDataHiddenLayer {
|
||||
partType: string // must be changed
|
||||
}
|
||||
|
||||
export interface IFigureDataSet {
|
||||
id: number
|
||||
gender: 'M' | 'F' | 'U'
|
||||
club: number // 0, 1, 2
|
||||
colorable: boolean // must be changed
|
||||
selectable: boolean // must be changed
|
||||
preselectable: boolean // must be changed
|
||||
sellable?: boolean // must be changed
|
||||
parts: IFigureDataPart[]
|
||||
hiddenLayers?: IFigureDataHiddenLayer[]
|
||||
}
|
||||
|
||||
export interface IFigureDataSetType {
|
||||
type: string // must be changed
|
||||
paletteId: number
|
||||
mandatoryF0: boolean // 0, 1
|
||||
mandatoryF1: boolean // 0, 1
|
||||
mandatoryM0: boolean // 0, 1
|
||||
mandatoryM1: boolean // 0, 1
|
||||
sets: IFigureDataSet[]
|
||||
}
|
||||
|
||||
export interface IFigureMapLibraryPart {
|
||||
id: number
|
||||
type: string
|
||||
}
|
||||
|
||||
export interface IFigureMapLibrary {
|
||||
id: string
|
||||
revision: number
|
||||
part: IFigureMapLibraryPart[]
|
||||
}
|
||||
|
||||
export interface IEffectMapLibrary {
|
||||
id: number
|
||||
lib: string
|
||||
type: string
|
||||
revision: number
|
||||
}
|
||||
|
||||
export interface IProduct {
|
||||
color: string
|
||||
name: string
|
||||
description: string
|
||||
}
|
4
src/types/index.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './Converters'
|
||||
export * from './SubConverters'
|
||||
export * from './Endpoint'
|
||||
export * from './Domain'
|
45
src/utils/fetchGameData.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { ResponseType } from '@tauri-apps/api/http'
|
||||
import { XMLParser } from 'fast-xml-parser'
|
||||
|
||||
import { GAME_ENDPOINTS, client } from '../config/ENDPOINTS'
|
||||
import type { DomainTypes } from '../types/Domain'
|
||||
import { convertXML } from '../mapping'
|
||||
import { parseData } from './parseData'
|
||||
|
||||
export const fetchGameData = async (
|
||||
domain: DomainTypes,
|
||||
callback: (message: string, error: boolean) => void,
|
||||
assetsOption = false
|
||||
): Promise<void> => {
|
||||
if (!assetsOption) {
|
||||
await Promise.all(
|
||||
GAME_ENDPOINTS(domain).map(async (endpoint) => {
|
||||
await client
|
||||
.get(endpoint.src, { responseType: ResponseType.Text })
|
||||
.then(async ({ data }) => {
|
||||
switch (endpoint.convert) {
|
||||
case 'XML':
|
||||
const convertedData = new XMLParser({
|
||||
ignoreAttributes: false,
|
||||
attributeNamePrefix: ''
|
||||
}).parse(data as string)
|
||||
|
||||
const XML2JSON = convertXML(convertedData, endpoint.src)
|
||||
|
||||
console.log(XML2JSON)
|
||||
|
||||
return await parseData(endpoint.fileName, XML2JSON)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
return callback(error, true)
|
||||
})
|
||||
})
|
||||
)
|
||||
} else {
|
||||
/* ASSETS_ENDPOINTS(domain).map((endpoint) => {
|
||||
client.get()
|
||||
}) */
|
||||
}
|
||||
}
|
19
src/utils/parseData.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { downloadDir } from '@tauri-apps/api/path'
|
||||
import { createDir, exists, writeTextFile } from '@tauri-apps/api/fs'
|
||||
|
||||
import { PROD_VERSION } from '../config/ENDPOINTS'
|
||||
|
||||
export const parseData = async (
|
||||
fileName: string,
|
||||
fileContent: string | object
|
||||
): Promise<void> => {
|
||||
const outputDir = (await downloadDir()).concat(String(PROD_VERSION))
|
||||
const fileDir = outputDir.concat(`/${fileName}.json`)
|
||||
|
||||
if (!(await exists(outputDir))) await createDir(outputDir)
|
||||
|
||||
await writeTextFile(
|
||||
fileDir,
|
||||
typeof fileContent === 'object' ? JSON.stringify(fileContent) : fileContent
|
||||
)
|
||||
}
|
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
13
tailwind.config.js
Normal file
@ -0,0 +1,13 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['./src/**/*.tsx'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
gamedata: { primary: '#FF7A00', secondary: '#FFA978' },
|
||||
gameAssets: { primary: '#423FD9', secondary: '#625FFA' }
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: []
|
||||
}
|
21
tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
9
tsconfig.node.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
26
vite.config.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig(async () => ({
|
||||
plugins: [react()],
|
||||
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
// prevent vite from obscuring rust errors
|
||||
clearScreen: false,
|
||||
// tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true
|
||||
},
|
||||
// to make use of `TAURI_DEBUG` and other env variables
|
||||
// https://tauri.studio/v1/api/config#buildconfig.beforedevcommand
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
build: {
|
||||
// Tauri supports es2021
|
||||
target: process.env.TAURI_PLATFORM == 'windows' ? 'chrome105' : 'safari13',
|
||||
// don't minify for debug builds
|
||||
minify: !process.env.TAURI_DEBUG ? 'esbuild' : false,
|
||||
// produce sourcemaps for debug builds
|
||||
sourcemap: !!process.env.TAURI_DEBUG
|
||||
}
|
||||
}))
|