refactor(components)
BREAKING CHANGES - Refactored `App.tsx` to import `Component` from `solid-js`, and use a new component `TitleBar`. - Added new component `AnimateView` under `src/components/design`, and renamed old `AnimateView` to `Loader`. - Added new component `Button` under `src/components/design`. - Added new component `Image` under `src/components/design`. - Moved old `Image`, `Loader`, and `Button` components under `src/components/design`. - Refactored `Downloader` component to use `Motion` from `@motionone/solid`, moved it under `Downloader` folder, and used it to create a slick hover effect. - Removed `Downloaders/Button`. Notes: - Used `createSignal` instead of `useState` for SolidJS in `Downloaders.tsx`. - Used `type` keyword to explicitly define the type of the component props or objects where it makes the code clearer.
This commit is contained in:
parent
6ba06e09d2
commit
d26b429ee8
17
src/App.tsx
17
src/App.tsx
@ -1,13 +1,18 @@
|
|||||||
import { Window } from './components/system'
|
import type { Component } from 'solid-js'
|
||||||
import { Downloaders } from './components/layout'
|
|
||||||
|
|
||||||
const Main: React.FC = () => {
|
import { Downloaders, TitleBar } from './components/layout'
|
||||||
|
|
||||||
|
const Main: Component = () => {
|
||||||
return (
|
return (
|
||||||
<Window>
|
<>
|
||||||
<span className='mb-20 text-white'>I would like to:</span>
|
<TitleBar />
|
||||||
|
|
||||||
|
<main class='relative flex h-full w-screen flex-col items-center justify-center bg-[#242424] py-20'>
|
||||||
|
<span class='mb-20 text-white'>I would like to:</span>
|
||||||
|
|
||||||
<Downloaders />
|
<Downloaders />
|
||||||
</Window>
|
</main>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
src/components/design/AnimateView/AnimateView.tsx
Normal file
22
src/components/design/AnimateView/AnimateView.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Show } from 'solid-js'
|
||||||
|
import type { Component } from 'solid-js'
|
||||||
|
import type { MotionComponentProps, Options as MotionProps } from '@motionone/solid'
|
||||||
|
import { Motion, Presence } from '@motionone/solid'
|
||||||
|
|
||||||
|
export interface AnimateViewProps extends MotionComponentProps {
|
||||||
|
condition: boolean
|
||||||
|
animation: MotionProps
|
||||||
|
class?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AnimateView: Component<AnimateViewProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<Presence>
|
||||||
|
<Show when={props.condition}>
|
||||||
|
<Motion.div {...props} initial={props.initial} animate={props.animate} exit={props.exit}>
|
||||||
|
{props.children}
|
||||||
|
</Motion.div>
|
||||||
|
</Show>
|
||||||
|
</Presence>
|
||||||
|
)
|
||||||
|
}
|
18
src/components/design/Button/Button.tsx
Normal file
18
src/components/design/Button/Button.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import type { Component, ComponentProps, JSXElement } from 'solid-js'
|
||||||
|
|
||||||
|
interface ButtonProps extends ComponentProps<'button'> {
|
||||||
|
icon: JSXElement
|
||||||
|
value: string
|
||||||
|
class?: string
|
||||||
|
handler?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Button: Component<ButtonProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<button onClick={props.handler} class={classNames(props.class, 'flex items-center justify-center gap-x-5')}>
|
||||||
|
{props.icon}
|
||||||
|
<span class='uppercase'>{props.value}</span>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
25
src/components/design/Image/Image.tsx
Normal file
25
src/components/design/Image/Image.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import type { Component } from 'solid-js'
|
||||||
|
|
||||||
|
interface ImageProps {
|
||||||
|
size?: number
|
||||||
|
pixelated?: boolean
|
||||||
|
src: string
|
||||||
|
class?: string
|
||||||
|
height?: number
|
||||||
|
width?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Image: Component<ImageProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
{...props}
|
||||||
|
elementtiming=''
|
||||||
|
fetchpriority='auto'
|
||||||
|
style={{ 'image-rendering': Boolean(props.pixelated) ? 'pixelated' : 'unset' }}
|
||||||
|
class={classNames(props.class, 'select-none')}
|
||||||
|
height={props.size ?? props.height}
|
||||||
|
width={props.size ?? props.width}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -1,21 +1,21 @@
|
|||||||
import type { HTMLMotionProps } from 'framer-motion'
|
import type { Component } from 'solid-js'
|
||||||
|
|
||||||
import { AnimateView } from '../../system'
|
import { Animation } from '../../../config'
|
||||||
|
import { AnimateView } from '../AnimateView'
|
||||||
|
|
||||||
interface LoaderProps extends HTMLMotionProps<'main'> {
|
interface LoaderProps {
|
||||||
|
class?: string
|
||||||
active: boolean
|
active: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Loader: React.FC<LoaderProps> = ({ active, ...rest }) => {
|
export const Loader: Component<LoaderProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<AnimateView
|
<AnimateView
|
||||||
condition={active}
|
class={props.class}
|
||||||
initial={{ opacity: 0, scale: 0 }}
|
condition={props.active}
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
animation={Animation.fadeInOut({ scale: [0, 1, 0], y: [1, 4, 1] })}>
|
||||||
exit={{ opacity: 0, scale: 0 }}
|
|
||||||
{...rest}>
|
|
||||||
<svg width='44' height='44' viewBox='0 0 44 44' xmlns='http://www.w3.org/2000/svg' stroke='#fff'>
|
<svg width='44' height='44' viewBox='0 0 44 44' xmlns='http://www.w3.org/2000/svg' stroke='#fff'>
|
||||||
<g fill='none' fillRule='evenodd' strokeWidth={2}>
|
<g fill='none' fill-rule='evenodd' stroke-width={2}>
|
||||||
<circle cx='22' cy='22' r='1'>
|
<circle cx='22' cy='22' r='1'>
|
||||||
<animate
|
<animate
|
||||||
attributeName='r'
|
attributeName='r'
|
||||||
|
@ -1 +1,4 @@
|
|||||||
export * from './Loader'
|
export * from './Loader'
|
||||||
|
export * from './AnimateView'
|
||||||
|
export * from './Image'
|
||||||
|
export * from './Button'
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
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,61 +1,57 @@
|
|||||||
|
import { Motion } from '@motionone/solid'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { AnimatePresence, motion } from 'framer-motion'
|
import type { Component, JSXElement } from 'solid-js'
|
||||||
import { useState } from 'react'
|
import { For, createSignal } from 'solid-js'
|
||||||
|
|
||||||
export interface IDownloaderContent {
|
import type { GameDataDownloader } from '../../../../config'
|
||||||
title: string
|
import { Animation } from '../../../../config'
|
||||||
features: string[]
|
import { AnimateView } from '../../../design'
|
||||||
}
|
|
||||||
|
|
||||||
interface DownloaderProps {
|
interface DownloaderProps {
|
||||||
className?: string
|
className?: string
|
||||||
children: React.ReactNode
|
children: JSXElement
|
||||||
content: IDownloaderContent
|
content: typeof GameDataDownloader
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Downloader: React.FC<DownloaderProps> = ({ className, children, content }) => {
|
export const Downloader: Component<DownloaderProps> = (props) => {
|
||||||
const [activeContent, setActiveContent] = useState(false)
|
const [activeContent, setActiveContent] = createSignal(false)
|
||||||
|
|
||||||
const handleActiveContent = (): void => {
|
const handleActiveContent = (): boolean => {
|
||||||
return setActiveContent(!activeContent)
|
return setActiveContent(!activeContent())
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
className={classNames(className, 'relative rounded-xl shadow-red-500 hover:shadow-2xl')}
|
class={classNames(props.className, 'relative rounded-xl shadow-red-500 hover:shadow-2xl')}
|
||||||
onMouseEnter={handleActiveContent}
|
onMouseEnter={handleActiveContent}
|
||||||
onMouseLeave={handleActiveContent}>
|
onMouseLeave={handleActiveContent}>
|
||||||
{children}
|
{props.children}
|
||||||
|
|
||||||
<AnimatePresence>
|
<AnimateView
|
||||||
{activeContent && (
|
condition={activeContent()}
|
||||||
<motion.ul
|
animation={Animation.fadeInOut()}
|
||||||
initial={{ opacity: 0 }}
|
class='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-center text-[12px] text-white'>
|
||||||
animate={{ opacity: 1, transition: { staggerChildren: 0.5 } }}
|
<Motion.h1
|
||||||
exit={{ opacity: 0 }}
|
|
||||||
className='pointer-events-none text-center 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 }}
|
initial={{ opacity: 0, y: -20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
exit={{ opacity: 0, y: -20 }}
|
exit={{ opacity: 0, y: -20 }}
|
||||||
className='mb-3 text-[16px]'>
|
class='mb-3 text-[16px]'>
|
||||||
{content.title}
|
{props.content.title}
|
||||||
</motion.h1>
|
</Motion.h1>
|
||||||
|
|
||||||
{content.features.map((feature) => {
|
<For each={props.content.features}>
|
||||||
|
{(feature) => {
|
||||||
return (
|
return (
|
||||||
<motion.span
|
<Motion.span
|
||||||
initial={{ opacity: 0, y: 50, scale: 0.75 }}
|
initial={{ opacity: 0, y: 50, scale: 0.75 }}
|
||||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||||
exit={{ opacity: 0, y: 50, scale: 0.75 }}
|
exit={{ opacity: 0, y: 50, scale: 0.75 }}>
|
||||||
key={feature}>
|
|
||||||
{feature}
|
{feature}
|
||||||
</motion.span>
|
</Motion.span>
|
||||||
)
|
)
|
||||||
})}
|
}}
|
||||||
</motion.ul>
|
</For>
|
||||||
)}
|
</AnimateView>
|
||||||
</AnimatePresence>
|
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import { Fragment, useState } from 'react'
|
import type { Component } from 'solid-js'
|
||||||
|
import { createSignal } from 'solid-js'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import { Image, Popup } from '../../system'
|
import type { ConvertionHandler } from '../../../types'
|
||||||
import { Button } from '../Button'
|
|
||||||
import { GameAssetsDownloader, GameDataDownloader } from '../../../config/GameDownloader'
|
|
||||||
import { handleConvertion } from '../../../tools/handleConvertion'
|
import { handleConvertion } from '../../../tools/handleConvertion'
|
||||||
import { Downloader } from './Downloader'
|
import { Animation, GameAssetsDownloader, GameDataDownloader } from '../../../config'
|
||||||
import type { ConvertionHandler } from '../../../types/global'
|
import { Button, Image, Loader } from '../../design'
|
||||||
import { Loader } from '../../design'
|
import { Popup } from '../Popup'
|
||||||
|
import { Downloader } from './Downloader/Downloader'
|
||||||
|
|
||||||
export const Downloaders: React.FC = () => {
|
export const Downloaders: Component = () => {
|
||||||
const [message, setMessage] = useState('')
|
const [message, setMessage] = createSignal('')
|
||||||
const [error, setError] = useState(false)
|
const [error, setError] = createSignal(false)
|
||||||
const [popup, setPopup] = useState(false)
|
const [popup, setPopup] = createSignal(false)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = createSignal(false)
|
||||||
|
|
||||||
const callback: ConvertionHandler = (message, state = 'idle') => {
|
const callback: ConvertionHandler = (message, state = 'idle') => {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -43,38 +43,39 @@ export const Downloaders: React.FC = () => {
|
|||||||
return callback(`Completed in: ${seconds} seconds`, 'success')
|
return callback(`Completed in: ${seconds} seconds`, 'success')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(Animation.fadeInOut({ scale: [0, 1, 0], y: [1, 4, 1] }))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<>
|
||||||
<Popup condition={popup}>
|
<Loader active={loading()} class='mt-10' />
|
||||||
|
<Popup condition={popup()}>
|
||||||
<span
|
<span
|
||||||
className={classNames('', {
|
class={classNames('', {
|
||||||
'text-red-600': error
|
'text-red-600': error
|
||||||
})}>
|
})}>
|
||||||
{message}
|
{message()}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<Loader active={loading} className='mt-10' />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
value='Close'
|
value='Close'
|
||||||
icon={<Image src='/icons/cross.png' />}
|
icon={<Image src='/icons/cross.png' />}
|
||||||
className={classNames('bg-red-600 mt-6 opacity-0 p-2 px-4 active:opacity-40 invisible text-white', {
|
class={classNames('invisible mt-6 bg-red-600 p-2 px-4 text-white opacity-0 active:opacity-40', {
|
||||||
'!opacity-100 !visible': !loading
|
'!visible !opacity-100': !loading()
|
||||||
})}
|
})}
|
||||||
handler={() => {
|
handler={() => {
|
||||||
return setPopup(!popup)
|
return setPopup(!popup())
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Popup>
|
</Popup>
|
||||||
|
|
||||||
<ul className='flex gap-x-8'>
|
<ul class='flex gap-x-8'>
|
||||||
<Downloader content={GameDataDownloader}>
|
<Downloader content={GameDataDownloader}>
|
||||||
<Image src='/images/Gamedata.png' />
|
<Image src='/images/Gamedata.png' />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
value='Download Gamedata'
|
value='Download Gamedata'
|
||||||
icon={<Image src='/icons/game.png' size={22} />}
|
icon={<Image src='/icons/game.png' size={22} />}
|
||||||
className='download-button border-gamedata-secondary bg-gamedata-primary shadow-gamedata-primary/20'
|
class='download-button border-gamedata-secondary bg-gamedata-primary shadow-gamedata-primary/20'
|
||||||
handler={downloadGameData}
|
handler={downloadGameData}
|
||||||
/>
|
/>
|
||||||
</Downloader>
|
</Downloader>
|
||||||
@ -84,11 +85,11 @@ export const Downloaders: React.FC = () => {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
value='Download GameAssets'
|
value='Download GameAssets'
|
||||||
icon={<Image src='/icons/picture.png' icon />}
|
icon={<Image src='/icons/picture.png' pixelated />}
|
||||||
className='download-button border-gameAssets-secondary bg-gameAssets-primary shadow-gameAssets-primary/40'
|
class='download-button border-gameAssets-secondary bg-gameAssets-primary shadow-gameAssets-primary/40'
|
||||||
/>
|
/>
|
||||||
</Downloader>
|
</Downloader>
|
||||||
</ul>
|
</ul>
|
||||||
</Fragment>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
23
src/components/layout/Popup/Popup.tsx
Normal file
23
src/components/layout/Popup/Popup.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import type { Component, JSXElement } from 'solid-js'
|
||||||
|
|
||||||
|
import { AnimateView } from '../../design'
|
||||||
|
import { Animation } from '../../../config'
|
||||||
|
|
||||||
|
interface PopupProps {
|
||||||
|
condition: boolean
|
||||||
|
children: JSXElement
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Popup: Component<PopupProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<AnimateView
|
||||||
|
animation={Animation.fadeInOut()}
|
||||||
|
class='absolute left-0 top-0 z-20 flex h-screen w-screen flex-col items-center justify-center bg-black/40 text-white backdrop-blur-xl transition-all'
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
condition={props.condition}>
|
||||||
|
{props.children}
|
||||||
|
</AnimateView>
|
||||||
|
)
|
||||||
|
}
|
41
src/components/layout/TitleBar/TitleBar.tsx
Normal file
41
src/components/layout/TitleBar/TitleBar.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { FiMaximize, FiMinus, FiX } from 'solid-icons/fi'
|
||||||
|
import { appWindow } from '@tauri-apps/api/window'
|
||||||
|
import type { Component } from 'solid-js'
|
||||||
|
|
||||||
|
import { Image } from '../../design'
|
||||||
|
|
||||||
|
export const TitleBar: Component = () => {
|
||||||
|
return (
|
||||||
|
<nav class='!z-50 flex h-[40px] w-full items-center justify-between bg-[#1f1f1f] text-white'>
|
||||||
|
<div
|
||||||
|
class='w-full select-none'
|
||||||
|
onMouseDown={async () => {
|
||||||
|
return await appWindow.startDragging()
|
||||||
|
}}>
|
||||||
|
<Image src='/Logo.svg' size={60} class='ml-3 p-1' />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class='flex h-full'>
|
||||||
|
<li
|
||||||
|
class='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-[#2a2a2a]'
|
||||||
|
onClick={async () => {
|
||||||
|
return await appWindow.minimize()
|
||||||
|
}}>
|
||||||
|
<FiMinus />
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='grid h-full w-14 cursor-not-allowed place-items-center opacity-40'>
|
||||||
|
<FiMaximize size={20} />
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li
|
||||||
|
class='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-red-500'
|
||||||
|
onClick={async () => {
|
||||||
|
return await appWindow.close()
|
||||||
|
}}>
|
||||||
|
<FiX />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
export * from './Button'
|
|
||||||
export * from './Downloaders'
|
export * from './Downloaders'
|
||||||
|
export * from './Popup'
|
||||||
|
export * from './TitleBar'
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import type { HTMLMotionProps } from 'framer-motion'
|
|
||||||
import { AnimatePresence, motion } from 'framer-motion'
|
|
||||||
|
|
||||||
export interface AnimateViewProps extends HTMLMotionProps<'main'> {
|
|
||||||
condition: boolean
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AnimateView: React.FC<AnimateViewProps> = ({ condition, children, ...rest }) => {
|
|
||||||
return (
|
|
||||||
<AnimatePresence>
|
|
||||||
{condition && (
|
|
||||||
<motion.main initial={rest.initial} animate={rest.animate} exit={rest.exit} {...rest}>
|
|
||||||
{children}
|
|
||||||
</motion.main>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
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,19 +0,0 @@
|
|||||||
import { AnimateView } from '../AnimateView'
|
|
||||||
|
|
||||||
interface PopupProps {
|
|
||||||
condition: boolean
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Popup: React.FC<PopupProps> = ({ condition, children }) => {
|
|
||||||
return (
|
|
||||||
<AnimateView
|
|
||||||
className='absolute flex text-white items-center flex-col transition-all justify-center z-20 top-0 left-0 w-screen h-screen bg-black/40 backdrop-blur-xl'
|
|
||||||
initial={{ opacity: 0 }}
|
|
||||||
animate={{ opacity: 1 }}
|
|
||||||
exit={{ opacity: 0 }}
|
|
||||||
condition={condition}>
|
|
||||||
{children}
|
|
||||||
</AnimateView>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import { Maximize, Minus, X } from 'react-feather'
|
|
||||||
import { appWindow } from '@tauri-apps/api/window'
|
|
||||||
|
|
||||||
import { Image } from '..'
|
|
||||||
|
|
||||||
export const TitleBar: React.FC = () => {
|
|
||||||
return (
|
|
||||||
<nav className='flex w-full h-[40px] !z-50 items-center justify-between bg-[#1f1f1f] text-white'>
|
|
||||||
<div
|
|
||||||
className='w-full select-none'
|
|
||||||
onMouseDown={async () => {
|
|
||||||
return await appWindow.startDragging()
|
|
||||||
}}>
|
|
||||||
<Image src='/Logo.svg' size={60} className='ml-3 p-1' />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul className='flex h-full'>
|
|
||||||
<li
|
|
||||||
className='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-[#2a2a2a]'
|
|
||||||
onClick={async () => {
|
|
||||||
return await appWindow.minimize()
|
|
||||||
}}>
|
|
||||||
<Minus />
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li className='grid h-full w-14 place-items-center cursor-not-allowed opacity-40'>
|
|
||||||
<Maximize size={20} />
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li
|
|
||||||
className='grid h-full w-14 cursor-pointer place-items-center transition-colors duration-[10ms] hover:bg-red-500'
|
|
||||||
onClick={async () => {
|
|
||||||
return await appWindow.close()
|
|
||||||
}}>
|
|
||||||
<X />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
import { Fragment } from 'react'
|
|
||||||
|
|
||||||
import { TitleBar } from '../TitleBar'
|
|
||||||
|
|
||||||
interface WindowProps {
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Window: React.FC<WindowProps> = ({ children }) => {
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<TitleBar />
|
|
||||||
|
|
||||||
<main className='relative flex items-center justify-center py-20 h-full w-screen flex-col bg-[#242424]'>
|
|
||||||
{children}
|
|
||||||
</main>
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
export * from './Window'
|
|
@ -1,5 +0,0 @@
|
|||||||
export * from './Image'
|
|
||||||
export * from './Window'
|
|
||||||
export * from './AnimateView'
|
|
||||||
export * from './TitleBar'
|
|
||||||
export * from './Popup'
|
|
23
src/config/Animation.ts
Normal file
23
src/config/Animation.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import type { Options, Variant } from '@motionone/solid'
|
||||||
|
|
||||||
|
const fadeInOut = (variant?: Variant): Options => {
|
||||||
|
const getVariantAtPosition = (pos: 0 | 1 | 2): Record<string, number> | null => {
|
||||||
|
if (variant == null) return null
|
||||||
|
|
||||||
|
const variantAtPos: Record<string, number> = {}
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(variant)) {
|
||||||
|
variantAtPos[key] = (value as number[])[pos as keyof typeof value]
|
||||||
|
}
|
||||||
|
|
||||||
|
return variantAtPos
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
initial: { opacity: 0, ...getVariantAtPosition(0) },
|
||||||
|
animate: { opacity: 1, ...getVariantAtPosition(1) },
|
||||||
|
exit: { opacity: 1, ...getVariantAtPosition(2) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Animation = { fadeInOut }
|
13
src/config/Domain.ts
Normal file
13
src/config/Domain.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export enum DomainTypes {
|
||||||
|
Portuguese = 'com.br',
|
||||||
|
Turkish = 'com.tr',
|
||||||
|
English = 'com',
|
||||||
|
German = 'de',
|
||||||
|
Spanish = 'es',
|
||||||
|
Finnish = 'fi',
|
||||||
|
French = 'fr',
|
||||||
|
Italian = 'it',
|
||||||
|
Dutch = 'nl'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SUPPORTED_LANGS = Object.keys(DomainTypes)
|
@ -1,6 +1,7 @@
|
|||||||
import { getClient, ResponseType } from '@tauri-apps/api/http'
|
import { getClient, ResponseType } from '@tauri-apps/api/http'
|
||||||
|
|
||||||
import type { DomainTypes, GameEndPointsTypes } from '../types'
|
import { DomainTypes } from './Domain'
|
||||||
|
import type { GamedataEndpoints } from '../tools/rusty'
|
||||||
|
|
||||||
const PROD_VERSION_REGEX = /(production-[^/]+)/im
|
const PROD_VERSION_REGEX = /(production-[^/]+)/im
|
||||||
const STABLE_PROD_VERSION = 'PRODUCTION-202304181630-471782382'
|
const STABLE_PROD_VERSION = 'PRODUCTION-202304181630-471782382'
|
||||||
@ -15,33 +16,19 @@ export const HABBO_GORDON_URL = `https://images.habbo.com/gordon/${PROD_VERSION
|
|||||||
|
|
||||||
export const client = await getClient()
|
export const client = await getClient()
|
||||||
await client
|
await client
|
||||||
.get(`${HABBO_URL('com')}/gamedata/external_variables/0`, {
|
.get(`${HABBO_URL(DomainTypes.English)}/gamedata/external_variables/0`, {
|
||||||
responseType: ResponseType.Text
|
responseType: ResponseType.Text
|
||||||
})
|
})
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
return (PROD_VERSION = (data as string).match(PROD_VERSION_REGEX)?.[0])
|
return (PROD_VERSION = (data as string).match(PROD_VERSION_REGEX)?.[0])
|
||||||
})
|
})
|
||||||
|
|
||||||
export const GAME_ENDPOINTS = (domain: DomainTypes): GameEndPointsTypes => {
|
export const GAMEDATA_ENDPOINTS = async (domain: DomainTypes): Promise<GamedataEndpoints[]> => {
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
src: `${HABBO_URL(domain)}/gamedata/figuredata/0`,
|
|
||||||
convert: 'XML',
|
|
||||||
fileName: 'FigureData'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: `${HABBO_GORDON_URL}/figuremap.xml`,
|
|
||||||
convert: 'XML',
|
|
||||||
fileName: 'FigureMap'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: `${HABBO_GORDON_URL}/effectmap.xml`,
|
|
||||||
convert: 'XML',
|
|
||||||
fileName: 'EffectMap'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
src: `${HABBO_URL(domain)}/gamedata/furnidata_json/0`,
|
src: `${HABBO_URL(domain)}/gamedata/furnidata_json/0`,
|
||||||
fileName: 'FurniData'
|
convert: 'JSON',
|
||||||
|
file_name: 'FurniData'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import type { IDownloaderContent } from '../components/layout/Downloaders/Downloader'
|
export const GameDataDownloader = {
|
||||||
|
|
||||||
export const GameDataDownloader: IDownloaderContent = {
|
|
||||||
title: 'Converts and bundles:',
|
title: 'Converts and bundles:',
|
||||||
features: ['XML/TXT to minified JSON files', 'Converts SWF files to Parquet']
|
features: ['XML/TXT to minified JSON files', 'Converts SWF files to Sprite']
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GameAssetsDownloader: IDownloaderContent = {
|
export const GameAssetsDownloader = {
|
||||||
title: 'Fetches PNG/JPEG:',
|
title: 'Fetches PNG/JPEG:',
|
||||||
features: [
|
features: [
|
||||||
'Badges + Badgeparts',
|
'Badges + Badgeparts',
|
||||||
|
5
src/config/index.ts
Normal file
5
src/config/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export * from './Animation'
|
||||||
|
export * from './Convertion'
|
||||||
|
export * from './Domain'
|
||||||
|
export * from './Endpoints'
|
||||||
|
export * from './GameDownloader'
|
@ -1,7 +1,7 @@
|
|||||||
import type { IFurni, IFurniData, IXML, KeyValuePairs } from '../types'
|
import type { IFurni, IFurniData, IXML, KeyValuePairs } from '../types'
|
||||||
|
|
||||||
export class FurniData {
|
export class FurniData {
|
||||||
public data: IFurniData = { roomItemTypes: [], wallItemTypes: [] }
|
public data: IFurniData = { floorItems: [], wallItems: [] }
|
||||||
public fileName: string
|
public fileName: string
|
||||||
|
|
||||||
constructor(data: IXML, fileName: string) {
|
constructor(data: IXML, fileName: string) {
|
||||||
@ -13,13 +13,13 @@ export class FurniData {
|
|||||||
|
|
||||||
private parseRoomItemTypes(roomItems: IFurni[]): void {
|
private parseRoomItemTypes(roomItems: IFurni[]): void {
|
||||||
for (const roomItem of roomItems) {
|
for (const roomItem of roomItems) {
|
||||||
this.data.roomItemTypes.push(roomItem)
|
this.data.floorItems.push(roomItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseWallItemTypes(wallItems: IFurni[]): void {
|
private parseWallItemTypes(wallItems: IFurni[]): void {
|
||||||
for (const wallItem of wallItems) {
|
for (const wallItem of wallItems) {
|
||||||
this.data.wallItemTypes.push(wallItem)
|
this.data.wallItems.push(wallItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,12 +33,12 @@ export class FurniData {
|
|||||||
public get classNamesAndRevisions(): KeyValuePairs<string, string> {
|
public get classNamesAndRevisions(): KeyValuePairs<string, string> {
|
||||||
const entries: KeyValuePairs<string, string> = {}
|
const entries: KeyValuePairs<string, string> = {}
|
||||||
|
|
||||||
for (const roomItem of this.data.roomItemTypes) {
|
for (const roomItem of this.data.floorItems) {
|
||||||
const { className, revision } = this.getClassNameRevision(roomItem)
|
const { className, revision } = this.getClassNameRevision(roomItem)
|
||||||
entries[className] = String(revision)
|
entries[className] = String(revision)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const wallItem of this.data.wallItemTypes) {
|
for (const wallItem of this.data.wallItems) {
|
||||||
const { className, revision } = this.getClassNameRevision(wallItem)
|
const { className, revision } = this.getClassNameRevision(wallItem)
|
||||||
entries[className] = String(revision)
|
entries[className] = String(revision)
|
||||||
}
|
}
|
||||||
|
@ -5,22 +5,33 @@ export const useOutSideClickEventHandler = (callback: () => void): RefObject<HTM
|
|||||||
const wrapper = useRef<HTMLDivElement>(null)
|
const wrapper = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleClickOutside = (event: KeyboardEvent): void => {
|
const handleClickOutside = (event: KeyboardEvent | MouseEvent): void => {
|
||||||
if (Boolean(wrapper.current?.contains(event.target as Node))) return
|
const currentEvent = event as KeyboardEvent
|
||||||
if (event.key !== 'Escape') return
|
|
||||||
|
if (
|
||||||
|
wrapper.current == null ||
|
||||||
|
Boolean(wrapper.current.contains(currentEvent.target as Node)) ||
|
||||||
|
currentEvent.key !== 'Escape'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
return callback()
|
return callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('click', (event: any) => {
|
window.addEventListener('click', (event) => {
|
||||||
return handleClickOutside(event)
|
return handleClickOutside(event)
|
||||||
})
|
})
|
||||||
|
|
||||||
window.addEventListener('keydown', (event: any) => {
|
window.addEventListener('keydown', (event) => {
|
||||||
return handleClickOutside(event)
|
return handleClickOutside(event)
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
return window.removeEventListener('click', (event: any) => {
|
window.removeEventListener('click', (event) => {
|
||||||
|
return handleClickOutside(event)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.removeEventListener('keydown', (event) => {
|
||||||
return handleClickOutside(event)
|
return handleClickOutside(event)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
9
src/index.tsx
Normal file
9
src/index.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { render } from 'solid-js/web'
|
||||||
|
|
||||||
|
import './styles.css'
|
||||||
|
import '@fontsource/press-start-2p'
|
||||||
|
import App from './App'
|
||||||
|
|
||||||
|
render(() => {
|
||||||
|
return <App />
|
||||||
|
}, document.getElementById('root') as HTMLElement)
|
12
src/main.tsx
12
src/main.tsx
@ -1,12 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
@ -1,6 +1,3 @@
|
|||||||
import { XMLParser } from 'fast-xml-parser'
|
|
||||||
|
|
||||||
import type { GameEndPointsTypes } from '../types'
|
|
||||||
import { FigureMap } from '../controllers/FigureMap'
|
import { FigureMap } from '../controllers/FigureMap'
|
||||||
import { EffectMap } from '../controllers/EffectMap'
|
import { EffectMap } from '../controllers/EffectMap'
|
||||||
import { convertTXT } from './convertTXT'
|
import { convertTXT } from './convertTXT'
|
||||||
@ -9,18 +6,18 @@ import { FurniData } from '../controllers/FurniData'
|
|||||||
import { Convertion } from '../config/Convertion'
|
import { Convertion } from '../config/Convertion'
|
||||||
import { parseData } from './parseData'
|
import { parseData } from './parseData'
|
||||||
|
|
||||||
export const fetchGamedataConfig = async (data: string, endpoint: GameEndPointsTypes[number]): Promise<unknown> => {
|
export const fetchGamedataConfig = async (data: string, endpoint: GamedataEndpoints): Promise<unknown> => {
|
||||||
switch (endpoint.convert) {
|
switch (endpoint.convert) {
|
||||||
case 'XML':
|
case 'XML':
|
||||||
const convertedData = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '' }).parse(data)
|
const convertedData = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '' }).parse(data)
|
||||||
let parsedData: FigureData | FigureMap | EffectMap | undefined
|
let parsedData: FigureData | FigureMap | EffectMap | undefined
|
||||||
|
|
||||||
if (endpoint.fileName === 'FigureData') {
|
if (endpoint.file_name === 'FigureData') {
|
||||||
parsedData = new FigureData(convertedData, endpoint.fileName)
|
parsedData = new FigureData(convertedData, endpoint.file_name)
|
||||||
} else if (endpoint.fileName === 'FigureMap') {
|
} else if (endpoint.file_name === 'FigureMap') {
|
||||||
parsedData = new FigureMap(convertedData, endpoint.fileName)
|
parsedData = new FigureMap(convertedData, endpoint.file_name)
|
||||||
} else if (endpoint.fileName === 'EffectMap') {
|
} else if (endpoint.file_name === 'EffectMap') {
|
||||||
parsedData = new EffectMap(convertedData, endpoint.fileName)
|
parsedData = new EffectMap(convertedData, endpoint.file_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return await parseData(Convertion.gamedataDir, parsedData?.fileName, parsedData?.data).catch((error) => {
|
return await parseData(Convertion.gamedataDir, parsedData?.fileName, parsedData?.data).catch((error) => {
|
||||||
@ -32,8 +29,8 @@ export const fetchGamedataConfig = async (data: string, endpoint: GameEndPointsT
|
|||||||
default: {
|
default: {
|
||||||
let parsedData: FurniData | undefined
|
let parsedData: FurniData | undefined
|
||||||
|
|
||||||
if (endpoint.fileName === 'FurniData') {
|
if (endpoint.file_name === 'FurniData') {
|
||||||
parsedData = new FurniData(JSON.parse(data), endpoint.fileName)
|
parsedData = new FurniData(JSON.parse(data), endpoint.file_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return await parseData(Convertion.gamedataDir, parsedData?.fileName, parsedData?.data).catch((error) => {
|
return await parseData(Convertion.gamedataDir, parsedData?.fileName, parsedData?.data).catch((error) => {
|
@ -1,9 +1,11 @@
|
|||||||
import { ResponseType } from '@tauri-apps/api/http'
|
import { ResponseType } from '@tauri-apps/api/http'
|
||||||
|
|
||||||
import { GAME_ENDPOINTS, client } from '../config/Endpoints'
|
import { GAMEDATA_ENDPOINTS, client } from '../config/Endpoints'
|
||||||
import type { ConvertionHandler } from '../types'
|
import type { ConvertionHandler } from '../types'
|
||||||
import type { DomainTypes } from '../types/Domain'
|
import type { DomainTypes } from '../config/Domain'
|
||||||
import { fetchGamedataConfig } from './fetchGamedataConfig'
|
import { parseData } from './parseData'
|
||||||
|
import { Convertion } from '../config/Convertion'
|
||||||
|
import { downloadGamedata } from './rusty'
|
||||||
|
|
||||||
export const handleConvertion = async (
|
export const handleConvertion = async (
|
||||||
domain: DomainTypes,
|
domain: DomainTypes,
|
||||||
@ -13,17 +15,24 @@ export const handleConvertion = async (
|
|||||||
if (!assetsOption) {
|
if (!assetsOption) {
|
||||||
callback('Initializing Gamedata configuration...', 'loading')
|
callback('Initializing Gamedata configuration...', 'loading')
|
||||||
|
|
||||||
|
const gameData = await GAMEDATA_ENDPOINTS(domain)
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
GAME_ENDPOINTS(domain).map(async (endpoint) => {
|
gameData.map(async (endpoint) => {
|
||||||
await client
|
if (endpoint.src.startsWith('http')) {
|
||||||
|
return await client
|
||||||
.get(endpoint.src, { responseType: ResponseType.Text })
|
.get(endpoint.src, { responseType: ResponseType.Text })
|
||||||
.then(async ({ data }) => {
|
.then(async ({ data }) => {
|
||||||
return await fetchGamedataConfig(data as string, endpoint)
|
return await downloadGamedata(data as string, endpoint).catch((error) => {
|
||||||
|
return console.log(error)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error)
|
|
||||||
return callback(error, 'error')
|
return callback(error, 'error')
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
return await parseData(Convertion.gamedataDir, endpoint.file_name, endpoint.src)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export * from './convertTXT'
|
|
@ -11,11 +11,10 @@ export const parseData = async (
|
|||||||
|
|
||||||
const fileDir = path.concat(`/${fileName}.json`)
|
const fileDir = path.concat(`/${fileName}.json`)
|
||||||
|
|
||||||
// By default, output files will be overwritten, and I cannot recursively remove the entire output folder
|
// By default, output files will be overwritten. I cannot recursively remove the entire output folder
|
||||||
// and create it again because it just won't parse files' contents for some reason
|
// and create it again because it just won't parse files' contents for some reason
|
||||||
|
|
||||||
if (!(await exists(Convertion.outputDir))) await createDir(Convertion.outputDir)
|
if (!(await exists(Convertion.gamedataDir))) await createDir(Convertion.gamedataDir, { recursive: true })
|
||||||
if (!(await exists(Convertion.gamedataDir))) await createDir(Convertion.gamedataDir)
|
|
||||||
|
|
||||||
return await writeFile(fileDir, typeof fileContent === 'object' ? JSON.stringify(fileContent) : fileContent)
|
return await writeFile(fileDir, typeof fileContent === 'object' ? JSON.stringify(fileContent) : fileContent)
|
||||||
}
|
}
|
||||||
|
17
src/tools/rusty.ts
Normal file
17
src/tools/rusty.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
__TAURI_INVOKE__<T>(cmd: string, args?: Record<string, unknown>): Promise<T>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const invoke = window.__TAURI_INVOKE__;
|
||||||
|
|
||||||
|
export function downloadGamedata(data: string, endpoint: GamedataEndpoints) {
|
||||||
|
return invoke<null>("download_gamedata", { data,endpoint })
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Converters = "FigureData" | "FigureMap" | "EffectMap" | "FurniData"
|
||||||
|
export type ConvertTypes = "TXT" | "XML" | "JSON"
|
||||||
|
export type GamedataEndpoints = { src: string; convert: ConvertTypes; file_name: Converters }
|
13
src/types/Converters.d.ts
vendored
13
src/types/Converters.d.ts
vendored
@ -1,4 +1,11 @@
|
|||||||
import type { IFigureDataPalette, IFigureDataSetType, IFigureMapLibrary, IFurni, IProduct } from './SubConverters'
|
import type {
|
||||||
|
IFigureDataPalette,
|
||||||
|
IFigureDataSetType,
|
||||||
|
IFigureMapLibrary,
|
||||||
|
IFloorItem,
|
||||||
|
IFurni,
|
||||||
|
IProduct
|
||||||
|
} from './SubConverters'
|
||||||
import type { KeyValuePairs } from './global'
|
import type { KeyValuePairs } from './global'
|
||||||
|
|
||||||
export interface IFigureData {
|
export interface IFigureData {
|
||||||
@ -12,8 +19,8 @@ export interface IFigureMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IFurniData {
|
export interface IFurniData {
|
||||||
roomItemTypes: IFurni[]
|
floorItems: IFloorItem[]
|
||||||
wallItemTypes: IFurni[]
|
wallItems: IFurni[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IEffectMap = KeyValuePairs<string, KeyValuePairs<string, string>>
|
export type IEffectMap = KeyValuePairs<string, KeyValuePairs<string, string>>
|
||||||
|
1
src/types/Domain.d.ts
vendored
1
src/types/Domain.d.ts
vendored
@ -1 +0,0 @@
|
|||||||
export type DomainTypes = 'com.br' | 'com.tr' | 'com' | 'de' | 'es' | 'fi' | 'fr' | 'it' | 'nl'
|
|
9
src/types/Endpoint.d.ts
vendored
9
src/types/Endpoint.d.ts
vendored
@ -1,9 +0,0 @@
|
|||||||
import type { XMLParser } from 'fast-xml-parser'
|
|
||||||
|
|
||||||
export type GameEndPointsTypes = Array<{
|
|
||||||
src: string
|
|
||||||
convert?: 'TXT' | 'XML'
|
|
||||||
fileName: string
|
|
||||||
}>
|
|
||||||
|
|
||||||
export type IXML = ReturnType<XMLParser['parse']>
|
|
44
src/types/SubConverters.d.ts
vendored
44
src/types/SubConverters.d.ts
vendored
@ -1,31 +1,33 @@
|
|||||||
import type { KeyValuePairs } from './global'
|
import type { KeyValuePairs } from './global'
|
||||||
|
|
||||||
|
export interface IFloorItemDimensions {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
defaultDirection: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IFloorItemPermissions {
|
||||||
|
canSitOn: boolean
|
||||||
|
canLayOn: boolean
|
||||||
|
canStandOn: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IFloorItem extends IFurni {
|
||||||
|
dimensions: IFloorItemDimensions
|
||||||
|
permissions: IFloorItemPermissions
|
||||||
|
}
|
||||||
|
|
||||||
export interface IFurni {
|
export interface IFurni {
|
||||||
id: number
|
id: number
|
||||||
classname: string
|
classname: string
|
||||||
revision: number
|
|
||||||
category?: string
|
|
||||||
defaultdir: number
|
|
||||||
xdim: number
|
|
||||||
ydim: number
|
|
||||||
partcolors?: { color: string[] }
|
|
||||||
name?: string
|
|
||||||
description?: string
|
description?: string
|
||||||
|
name?: string
|
||||||
|
furniLine?: string
|
||||||
|
customParams?: string
|
||||||
adurl?: string
|
adurl?: string
|
||||||
offerid?: number
|
offerID?: number
|
||||||
buyout: boolean
|
excludeDynamic: boolean
|
||||||
rentofferid: number
|
specialType: number
|
||||||
rentbuyout: boolean
|
|
||||||
bc: boolean
|
|
||||||
excludeddynamic: boolean
|
|
||||||
customparams?: string
|
|
||||||
specialtype: number
|
|
||||||
canstandon: boolean
|
|
||||||
cansiton: boolean
|
|
||||||
canlayon: boolean
|
|
||||||
furniline?: string
|
|
||||||
environment?: string
|
|
||||||
rare: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Club = 'idle' | 'HC' | 'VIP'
|
export type Club = 'idle' | 'HC' | 'VIP'
|
||||||
|
4
src/types/global.d.ts
vendored
4
src/types/global.d.ts
vendored
@ -1,6 +1,2 @@
|
|||||||
export type StateTypes = 'idle' | 'loading' | 'error' | 'success'
|
export type StateTypes = 'idle' | 'loading' | 'error' | 'success'
|
||||||
export type ConvertionHandler = (message: string, state: StateTypes) => void
|
export type ConvertionHandler = (message: string, state: StateTypes) => void
|
||||||
|
|
||||||
export type KeyValuePairs<KeyType extends number | string, ValueType> = {
|
|
||||||
[key in KeyType]: ValueType
|
|
||||||
}
|
|
||||||
|
2
src/types/index.d.ts
vendored
2
src/types/index.d.ts
vendored
@ -1,5 +1,3 @@
|
|||||||
export * from './Converters'
|
export * from './Converters'
|
||||||
export * from './SubConverters'
|
export * from './SubConverters'
|
||||||
export * from './Endpoint'
|
|
||||||
export * from './Domain'
|
|
||||||
export * from './global'
|
export * from './global'
|
||||||
|
1
src/vite-env.d.ts
vendored
1
src/vite-env.d.ts
vendored
@ -1 +0,0 @@
|
|||||||
/// <reference types="vite/client" />
|
|
Loading…
Reference in New Issue
Block a user