Compare commits

...

1 Commits

Author SHA1 Message Date
Zephyr Lykos
178664ed83
refactor: migrate toolchain, part 1
- Switched to pnpm
- Updated to typescript 4.9.5
- JSX transforms switched to react-jsx
- Use swc for typescript transforms
- Remove deprecated dependencies
- Cleanup unused types
- Some ESM fixes
- PostCSS config now lives in package.json
- Bump support target

TODO:
- switch to vite or plain esbuild
- jest to vitest / uvu
- jquery to cash-dom
- pure ESM (lodash-es, etc.)
- drop prettier & husky (lint-staged is okay)
- drop wasm cli & xterm.js
- update bootstrap
2023-07-10 19:58:18 +08:00
119 changed files with 11873 additions and 10148 deletions

View File

@ -21,7 +21,7 @@ WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY postcss.config.js tsconfig.build.json tsconfig.json webpack.config.ts ./
COPY tsconfig.build.json tsconfig.json webpack.config.ts ./
COPY tools/*Plugin.ts ./tools/
COPY resources ./resources

View File

@ -6,6 +6,7 @@
"type": "git",
"url": "https://github.com/bs-community/blessing-skin-server"
},
"type": "module",
"author": "printempw",
"license": "MIT",
"private": true,
@ -21,92 +22,86 @@
"prepare": "husky install"
},
"dependencies": {
"@emotion/react": "^11.0.0",
"@emotion/styled": "^11.0.0",
"@fortawesome/fontawesome-free": "^6.3.0",
"@hot-loader/react-dom": "^17.0.0",
"@tweenjs/tween.js": "^18.5.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@fortawesome/fontawesome-free": "^6.4.0",
"@hot-loader/react-dom": "^17.0.2",
"@tweenjs/tween.js": "^21.0.0",
"admin-lte": "^3.2.0",
"blessing-skin-shell": "^0.3.4",
"bootstrap": "^4.6.1",
"cac": "6.6.1",
"cli-spinners": "^2.5.0",
"clsx": "^1.1.1",
"echarts": "^5.1.2",
"events": "^3.2.0",
"immer": "^7.0.4",
"jquery": "^3.6.0",
"bootstrap": "^4.6.2",
"cac": "6.7.14",
"cli-spinners": "^2.9.0",
"clsx": "^1.2.1",
"echarts": "^5.4.2",
"immer": "^10.0.2",
"jquery": "^3.7.0",
"lodash.debounce": "^4.0.8",
"nanoid": "^3.1.9",
"prompts": "^2.4.0",
"react": "^17.0.1",
"react-autosuggest": "^10.0.2",
"react-dom": "^17.0.1",
"react-draggable": "^4.4.2",
"react-hot-loader": "^4.12.21",
"react-loading-skeleton": "^2.1.1",
"nanoid": "^4.0.2",
"prompts": "^2.4.2",
"react": "^17.0.2",
"react-autosuggest": "^10.1.0",
"react-dom": "^17.0.2",
"react-draggable": "^4.4.5",
"react-hot-loader": "^4.13.1",
"react-loading-skeleton": "^3.3.1",
"react-use": "^17.4.0",
"reaptcha": "^1.7.2",
"rxjs": "^6.5.5",
"skinview-utils": "^0.5.5",
"skinview3d": "^3.0.0-alpha.1",
"spectre.css": "^0.5.8",
"use-immer": "^0.4.2",
"xterm": "^4.6.0",
"xterm-addon-fit": "^0.4.0"
"reaptcha": "^1.12.1",
"rxjs": "^7.8.1",
"skinview-utils": "^0.7.0",
"skinview3d": "3.0.0-alpha.1",
"spectre.css": "^0.5.9",
"use-immer": "^0.9.0",
"xterm": "^5.2.1",
"xterm-addon-fit": "^0.7.0"
},
"devDependencies": {
"@gplane/tsconfig": "^4.2.0",
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@types/bootstrap": "^4.3.3",
"@types/css-minimizer-webpack-plugin": "^1.1.0",
"@types/jest": "^26.0.23",
"@types/jquery": "^3.5.13",
"@types/js-yaml": "^3.12.4",
"@types/lodash.debounce": "^4.0.6",
"@types/mini-css-extract-plugin": "^1.2.1",
"@types/prompts": "^2.0.9",
"@types/react": "^16.9.35",
"@types/react-autosuggest": "^9.3.14",
"@types/react-dom": "^16.9.8",
"@types/tween.js": "^18.5.0",
"@types/webpack-dev-server": "^3.11.0",
"@typescript-eslint/eslint-plugin": "^3.6.0",
"@typescript-eslint/parser": "^3.6.0",
"autoprefixer": "^10.2.6",
"css-loader": "^5.2.6",
"css-minimizer-webpack-plugin": "^3.0.1",
"eslint": "^7.4.0",
"@gplane/tsconfig": "^5.0.0",
"@swc/register": "^0.1.10",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.5",
"@types/bootstrap": "^5.2.6",
"@types/jest": "^29.5.2",
"@types/jquery": "^3.5.16",
"@types/js-yaml": "^4.0.5",
"@types/lodash.debounce": "^4.0.7",
"@types/prompts": "^2.4.4",
"@types/react": "17",
"@types/react-autosuggest": "^10.1.6",
"@types/react-dom": "^17.0.20",
"@types/testing-library__jest-dom": "^5.14.7",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
"autoprefixer": "^10.4.14",
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"eslint": "^8.44.0",
"eslint-formatter-beauty": "^3.0.0",
"eslint-plugin-react-hooks": "^4.3.0",
"html-webpack-plugin": "^5.3.1",
"husky": "^7.0.4",
"jest": "^27.0.4",
"jest-extended": "^0.11.5",
"js-yaml": "^3.13.1",
"mini-css-extract-plugin": "^1.6.0",
"postcss": "^8.3.0",
"postcss-loader": "^5.3.0",
"prettier": "^2.3.0",
"eslint-plugin-react-hooks": "^4.6.0",
"html-webpack-plugin": "^5.5.3",
"husky": "^8.0.3",
"jest": "^29.6.1",
"jest-environment-jsdom": "^29.6.1",
"jest-extended": "^4.0.0",
"js-yaml": "^4.1.0",
"mini-css-extract-plugin": "^2.7.6",
"postcss": "^8.4.25",
"postcss-loader": "^7.3.3",
"prettier": "^2.8.8",
"pretty-quick": "^3.1.3",
"style-loader": "^2.0.0",
"ts-jest": "^27.0.2",
"ts-loader": "^9.2.2",
"ts-node": "^10.0.0",
"typescript": "^4.3.2",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0",
"webpack-dev-server": "^3.11.2"
},
"resolutions": {
"kleur": "^4.1.3"
"style-loader": "^3.3.3",
"ts-jest": "^29.1.1",
"ts-loader": "^9.4.4",
"typescript": "^4.9.5",
"webpack": "^5.88.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"browserslist": [
"> 1%",
"not dead",
"not ie 11",
"Chrome > 52"
"Chrome >= 87",
"Firefox >= 84",
"iOS >= 12.5",
"not dead"
],
"prettier": {
"printWidth": 80,
@ -115,17 +110,13 @@
"trailingComma": "all",
"tabWidth": 2
},
"postcss": {
"autoprefixer": {}
},
"jest": {
"preset": "ts-jest",
"resetMocks": true,
"testEnvironment": "jsdom",
"moduleFileExtensions": [
"js",
"ts",
"tsx",
"json",
"node"
],
"moduleNameMapper": {
"\\.css$": "<rootDir>/resources/assets/tests/__mocks__/style.ts",
"\\.(png|webp)$": "<rootDir>/resources/assets/tests/__mocks__/file.ts",

11664
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
module.exports = {
plugins: [
require('autoprefixer'),
],
}

View File

@ -1,5 +1,3 @@
import React from 'react'
type AlertType = 'success' | 'info' | 'warning' | 'danger'
const icons = new Map<AlertType, string>([

View File

@ -1,5 +1,3 @@
import React from 'react'
interface Props {
title?: string
onClick: React.MouseEventHandler<HTMLAnchorElement>

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'
import * as fetch from '@/scripts/net'
interface Props {

View File

@ -1,5 +1,5 @@
/** @jsxImportSource @emotion/react */
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import Autosuggest from 'react-autosuggest'
import { css } from '@emotion/react'
import { emit } from '@/scripts/event'

View File

@ -1,5 +1,3 @@
import React from 'react'
const Loading = () => (
<div className="container text-center" title="Loading...">
<i className="fas fa-sync fa-spin"></i>

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react'
import { useState, useEffect, useRef } from 'react'
import $ from 'jquery'
import 'bootstrap'
import { t } from '../scripts/i18n'
@ -66,9 +66,14 @@ const Modal: React.FC<ModalOptions & Props> = (props) => {
return
}
const onHidden = () => props.onClose?.()
const onClose =
props.onClose ||
(() => {
/* noop */
})
const onHidden = () => onClose()
const el = $(ref.current!)
const el = $(ref.current as HTMLElement)
el.on('hidden.bs.modal', onHidden)
return () => {
@ -92,28 +97,27 @@ const Modal: React.FC<ModalOptions & Props> = (props) => {
}
props.onConfirm?.({ value })
$(ref.current!).modal('hide')
$(ref.current as HTMLElement).modal('hide')
// The "hidden.bs.modal" event can't be trigged automatically when testing.
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') {
$(ref.current!).trigger('hidden.bs.modal')
$(ref.current as HTMLElement).trigger('hidden.bs.modal')
}
}
const dismiss = () => {
props.onDismiss?.()
$(ref.current!).modal('hide')
$(ref.current as HTMLElement).modal('hide')
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') {
$(ref.current!).trigger('hidden.bs.modal')
$(ref.current as HTMLElement).trigger('hidden.bs.modal')
}
}
useEffect(() => {
if (show) {
setTimeout(() => $(ref.current!).modal('show'), 50)
setTimeout(() => $(ref.current as HTMLElement).modal('show'), 50)
}
}, [show])

View File

@ -1,4 +1,3 @@
import React from 'react'
import ModalContent from './ModalContent'
import ModalInput from './ModalInput'
import type { Props as ContentProps } from './ModalContent'

View File

@ -1,5 +1,3 @@
import React from 'react'
export interface Props {
text?: string
dangerousHTML?: string

View File

@ -1,5 +1,3 @@
import React from 'react'
export interface Props {
flexFooter?: boolean
okButtonText?: string

View File

@ -1,5 +1,3 @@
import React from 'react'
export interface Props {
title?: string
}

View File

@ -1,4 +1,4 @@
import React, { HTMLAttributes } from 'react'
import type { HTMLAttributes } from 'react'
export interface Props {
inputType?: string

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import PaginationItem from './PaginationItem'

View File

@ -1,5 +1,3 @@
import React from 'react'
interface Props {
disabled?: boolean
active?: boolean

View File

@ -1,5 +1,5 @@
/** @jsxImportSource @emotion/react */
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import { css } from '@emotion/react'
export type ToastType = 'success' | 'info' | 'warning' | 'error'

View File

@ -1,5 +1,5 @@
/** @jsxImportSource @emotion/react */
import React, { useState, useEffect, useRef } from 'react'
import { useState, useEffect, useRef } from 'react'
import { useMeasure } from 'react-use'
import { css } from '@emotion/react'
import styled from '@emotion/styled'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
const ViewerSkeleton: React.FC = () => (

View File

@ -30,8 +30,7 @@ if (route) {
</React.Suspense>
</React.StrictMode>
)
const c =
typeof route.el === 'string' ? document.querySelector(route.el) : route.el
const c = document.querySelector(route.el)
ReactDOM.render(<Root />, c)
}
}

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef } from 'react'
import { useEffect, useRef } from 'react'
import ReactDOM from 'react-dom'
import styled from '@emotion/styled'
import { Terminal } from 'xterm'
@ -57,10 +57,8 @@ const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
const terminal = new Terminal()
const fitAddon = new FitAddon()
terminal.loadAddon(fitAddon)
terminal.setOption(
'fontFamily',
'Monaco, Consolas, "Roboto Mono", "Noto Sans", "Droid Sans Mono"',
)
terminal.options.fontFamily =
'Monaco, Consolas, "Roboto Mono", "Noto Sans", "Droid Sans Mono"'
terminal.open(el)
fitAddon.fit()
@ -83,6 +81,7 @@ const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
if (stack?.includes('outputHelp')) {
terminal.writeln(data.replace(/\n/g, '\r\n'))
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
originalLogger(data, ...args)
}
}

View File

@ -22,7 +22,7 @@ export default async function pacman(stdio: Stdio, args: string[]) {
const { options } = program.parse(['', ''].concat(args), { run: false })
const opts: Options = options
/* istanbul ignore else */
if (opts.sync) {
await install(opts.sync, stdio)
} else if (opts.remove) {

View File

@ -1,7 +1,6 @@
import type { Stdio } from 'blessing-skin-shell'
import * as event from '../event'
/* istanbul ignore next */
export function hackStdin() {
if (process.env.NODE_ENV === 'test') {
return process.stdin
@ -24,7 +23,6 @@ export function hackStdin() {
} as NodeJS.ReadStream & { _off(): void }
}
/* istanbul ignore next */
export function hackStdout(stdio: Stdio) {
return {
write(msg: string) {

View File

@ -1,4 +1,3 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import DarkModeButton from '@/components/DarkModeButton'

View File

@ -1,4 +1,3 @@
import React from 'react'
import ReactDOM from 'react-dom'
import EmailVerification from '@/views/widgets/EmailVerification'

View File

@ -1,6 +1,6 @@
export function getExtraData(): Record<string, any> {
const jsonElement = document.querySelector('#blessing-extra')
/* istanbul ignore next */
if (jsonElement) {
return JSON.parse(jsonElement.textContent ?? '{}')
} else {

View File

@ -2,7 +2,7 @@ import { getExtraData } from './extra'
export function scrollHander() {
const header = document.querySelector('.navbar')
/* istanbul ignore else */
if (header) {
window.addEventListener('scroll', () => {
if (window.scrollY >= (window.innerHeight * 2) / 3) {
@ -14,7 +14,6 @@ export function scrollHander() {
}
}
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') {
const { transparent_navbar } = getExtraData() as {
transparent_navbar: boolean

View File

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react'
import * as fetch from '../net'
import { Texture, TextureType } from '../types'
import { type Texture, TextureType } from '../types'
export default function useTexture() {
const [tid, setTid] = useState(0)

View File

@ -8,7 +8,6 @@ export function t(key: string, parameters = Object.create(null)): string {
let result = ''
for (const segment of segments) {
/* istanbul ignore next */
const middle = temp?.[segment]
if (!middle) {
return key
@ -20,9 +19,11 @@ export function t(key: string, parameters = Object.create(null)): string {
}
}
/* eslint-disable @typescript-eslint/no-unsafe-argument */
Object.keys(parameters).forEach(
(slot) => (result = result.replace(`:${slot}`, parameters[slot])),
)
/* eslint-enable @typescript-eslint/no-unsafe-argument */
return result
}

View File

@ -18,5 +18,5 @@ export async function logout() {
}
const button = document.querySelector('#logout-button')
/* istanbul ignore next */
button?.addEventListener('click', logout)

View File

@ -1,6 +1,5 @@
import React from 'react'
import ReactDOM from 'react-dom'
import Modal, { ModalOptions, ModalResult } from '../components/Modal'
import Modal, { type ModalOptions, type ModalResult } from '../components/Modal'
export function showModal(options: ModalOptions = {}): Promise<ModalResult> {
return new Promise((resolve, reject) => {

View File

@ -80,7 +80,7 @@ export async function walkFetch(request: Request): Promise<any> {
message = `${message}<br><details>${trace}</details>`
}
throw new HTTPError(message || body, cloned)
throw new HTTPError(message || (body as string), cloned)
} catch (error: any) {
emit('fetchError', error)
await showModal({
@ -95,7 +95,10 @@ export async function walkFetch(request: Request): Promise<any> {
}
}
export function get<T = any>(url: string, params = empty): Promise<T> {
export function get<T = any>(
url: string,
params: Record<string, any> = empty,
): Promise<T> {
emit('beforeFetch', {
method: 'GET',
url,

View File

@ -1,4 +1,3 @@
import React from 'react'
import ReactDOM from 'react-dom'
import NotificationsList from '@/views/widgets/NotificationsList'

View File

@ -3,7 +3,6 @@ import { Toast } from './toast'
export const toast = new Toast()
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') {
afterEach(() => {
toast.clear()

View File

@ -1,5 +1,3 @@
import React from 'react'
export default [
{
path: 'user',

View File

@ -1,6 +1,5 @@
import { loadSkinToCanvas } from 'skinview-utils'
/* istanbul ignore next */
function checkPixel(
context: CanvasRenderingContext2D,
x: number,
@ -15,7 +14,6 @@ function checkPixel(
)
}
/* istanbul ignore next */
export function isAlex(texture: string): Promise<boolean> {
return new Promise((resolve) => {
const image = new Image()

View File

@ -1,8 +1,9 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import ReactDOM from 'react-dom'
import { nanoid } from 'nanoid'
import * as emitter from './event'
import ToastBox, { ToastType } from '../components/Toast'
import ToastBox from '../components/Toast'
import type { ToastType } from '../components/Toast'
type QueueElement = { id: string; type: ToastType; message: string }
type ToastQueue = QueueElement[]

View File

@ -38,9 +38,13 @@ export function registerNavbarPicker(
const navbar = document.querySelector<HTMLElement>('.wrapper > nav')
const picker = document.querySelector<HTMLDivElement>('#navbar-color-picker')
/* istanbul ignore next */
if (navbar && picker) {
registerNavbarPicker(navbar, picker, blessing.extra.navbar || 'white')
registerNavbarPicker(
navbar,
picker,
(blessing.extra.navbar as string) || 'white',
)
}
export function registerSidebarPicker(
@ -73,11 +77,10 @@ const darkPicker = document.querySelector<HTMLDivElement>(
const lightPicker = document.querySelector<HTMLDivElement>(
'#sidebar-light-picker',
)
/* istanbul ignore next */
if (sidebar && darkPicker && lightPicker) {
registerSidebarPicker(
sidebar,
{ dark: darkPicker, light: lightPicker },
blessing.extra.sidebar || 'dark-primary',
(blessing.extra.sidebar as string) || 'dark-primary',
)
}

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import { showModal } from '@/scripts/notify'
import type { Player } from '@/scripts/types'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton'
import { Box } from './styles'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'
import { t } from '@/scripts/i18n'
import { TextureType } from '@/scripts/types'
import Modal from '@/components/Modal'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import type { Player } from '@/scripts/types'
import ButtonEdit from '@/components/ButtonEdit'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useLayoutEffect } from 'react'
import { useState, useEffect, useLayoutEffect } from 'react'
import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer'
import useIsLargeScreen from '@/scripts/hooks/useIsLargeScreen'
@ -47,6 +47,7 @@ const PlayersManagement: React.FC = () => {
useEffect(() => {
getPlayers()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [page])
const handleModeChange = (event: React.ChangeEvent<HTMLInputElement>) => {

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import { t } from '@/scripts/i18n'
import type { Plugin } from './types'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer'
import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import type { Plugin } from './types'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useMemo } from 'react'
import { useState, useEffect, useMemo } from 'react'
import { hot } from 'react-hot-loader/root'
import { enableMapSet } from 'immer'
import { useImmer } from 'use-immer'

View File

@ -1,8 +1,7 @@
import React from 'react'
import styled from '@emotion/styled'
import { t } from '@/scripts/i18n'
import type { Texture } from '@/scripts/types'
import { Report, Status } from './types'
import { type Report, Status } from './types'
const Card = styled.div`
width: 240px;

View File

@ -3,7 +3,7 @@ import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { Paginator, Texture, TextureType } from '@/scripts/types'
import { type Paginator, type Texture, TextureType } from '@/scripts/types'
import { toast, showModal } from '@/scripts/notify'
import Loading from '@/components/Loading'
import Pagination from '@/components/Pagination'
@ -37,6 +37,7 @@ const ReportsManagement: React.FC = () => {
useEffect(() => {
getReports()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [page])
const handleQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => {

View File

@ -1,5 +1,5 @@
import styled from '@emotion/styled'
import React from 'react'
import { t } from '@/scripts/i18n'
import type { Line } from './types'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer'
import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,4 @@
import { post, ResponseBody } from '../../scripts/net'
import { post, type ResponseBody } from '../../scripts/net'
import { showModal } from '../../scripts/notify'
import { t } from '../../scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import type { User } from '@/scripts/types'
import { Box, Icon, InfoTable } from './styles'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton'
import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import type { User } from '@/scripts/types'
import ButtonEdit from '@/components/ButtonEdit'

View File

@ -1,11 +1,11 @@
import React, { useState, useEffect, useLayoutEffect } from 'react'
import { useState, useEffect, useLayoutEffect } from 'react'
import { hot } from 'react-hot-loader/root'
import { useImmer } from 'use-immer'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useIsLargeScreen from '@/scripts/hooks/useIsLargeScreen'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { User, UserPermission, Paginator } from '@/scripts/types'
import { type User, UserPermission, type Paginator } from '@/scripts/types'
import { toast, showModal } from '@/scripts/notify'
import urls from '@/scripts/urls'
import type { Props as ModalInputProps } from '@/components/ModalInput'

View File

@ -1,5 +1,5 @@
import { t } from '@/scripts/i18n'
import { User, UserPermission } from '@/scripts/types'
import { type User, UserPermission } from '@/scripts/types'
export function humanizePermission(permission: UserPermission): string {
switch (permission) {

View File

@ -1,4 +1,4 @@
import React, { useState, useRef } from 'react'
import { useState, useRef } from 'react'
import { hot } from 'react-hot-loader/root'
import useEmitMounted from '@/scripts/hooks/useEmitMounted'
import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect } from 'react'
import { useState, useRef, useEffect } from 'react'
import { hot } from 'react-hot-loader/root'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,4 @@
import React, { useState, useRef } from 'react'
import { useState, useRef } from 'react'
import { hot } from 'react-hot-loader/root'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'
import { hot } from 'react-hot-loader/root'
import useEmitMounted from '@/scripts/hooks/useEmitMounted'
import { t } from '@/scripts/i18n'

View File

@ -1,5 +1,3 @@
import React from 'react'
interface Props {
active?: boolean
bg?: string

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import { TextureType } from '@/scripts/types'
import Button from './Button'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import { t } from '@/scripts/i18n'
import * as cssUtils from '@/styles/utils'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import type { ClosetItem as ClosetItemType } from '@/scripts/types'
import setAsAvatar from './setAsAvatar'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton'
import { Card, DropdownButton } from './styles'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import $ from 'jquery'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from 'react'
import { useState, useEffect, useRef } from 'react'
import { hot } from 'react-hot-loader/root'
import debounce from 'lodash.debounce'
import useEmitMounted from '@/scripts/hooks/useEmitMounted'
@ -6,9 +6,9 @@ import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { showModal, toast } from '@/scripts/notify'
import {
ClosetItem as Item,
Texture,
Paginator,
type ClosetItem as Item,
type Texture,
type Paginator,
TextureType,
} from '@/scripts/types'
import urls from '@/scripts/urls'
@ -22,10 +22,8 @@ import removeClosetItem from './removeClosetItem'
type Category = 'skin' | 'cape'
const updater = debounce(
<T extends unknown>(
value: React.SetStateAction<T>,
setter: React.Dispatch<React.SetStateAction<T>>,
) => setter(value),
(value: React.SetStateAction<any>, setter: React.Dispatch<typeof value>) =>
setter(value),
350,
)
@ -47,7 +45,7 @@ const Closet: React.FC = () => {
useEffect(() => {
const element = containerRef.current
/* istanbul ignore next */
if (element) {
const { width } = element.getBoundingClientRect()
if (width >= 500) {

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback } from 'react'
import { useState, useEffect, useCallback } from 'react'
import styled from '@emotion/styled'
import { hot } from 'react-hot-loader/root'
import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'
import { t } from '@/scripts/i18n'
import Modal from '@/components/Modal'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { t } from '@/scripts/i18n'
import ButtonEdit from '@/components/ButtonEdit'
import type { App } from './types'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import Skeleton from 'react-loading-skeleton'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { toast } from '@/scripts/notify'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'
import { t } from '@/scripts/i18n'
import Modal from '@/components/Modal'

View File

@ -1,4 +1,3 @@
import React from 'react'
import styled from '@emotion/styled'
import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import { hot } from 'react-hot-loader/root'
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra'
import useEmitMounted from '@/scripts/hooks/useEmitMounted'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { toast } from '@/scripts/notify'

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import { useState, useEffect } from 'react'
import * as fetch from '@/scripts/net'
import { showModal } from '@/scripts/notify'

View File

@ -1,11 +1,3 @@
declare module '*.styl' {
export default {} as Record<string, string>
}
declare module '*.scss' {
export default {} as Record<string, string>
}
declare module '*.png' {
export default ''
}

View File

@ -1,5 +1,5 @@
import React from 'react'
import type { ReaptchaProps } from 'reaptcha'
import type ReaptchaProps from 'reaptcha'
class Reaptcha extends React.Component<ReaptchaProps, {}> {
execute() {

View File

@ -15,7 +15,7 @@ describe('picture captcha', () => {
expect(await ref.current?.execute()).toBe('abc')
})
it('refresh on click', async () => {
it('refresh on click', () => {
const spy = jest.spyOn(Date, 'now')
const ref = React.createRef<Captcha>()
@ -25,7 +25,7 @@ describe('picture captcha', () => {
expect(spy).toBeCalled()
})
it('refresh programatically', async () => {
it('refresh programatically', () => {
const spy = jest.spyOn(Date, 'now')
const ref = React.createRef<Captcha>()
@ -53,7 +53,7 @@ describe('recaptcha', () => {
expect(value).toBe('token')
})
it('refresh programatically', async () => {
it('refresh programatically', () => {
const spy = jest.spyOn(Reaptcha.prototype, 'reset')
const ref = React.createRef<Captcha>()

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent, waitFor } from '@testing-library/react'
import * as fetch from '@/scripts/net'
import DarkModeButton from '@/components/DarkModeButton'

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'
import { render, fireEvent } from '@testing-library/react'
import { on } from '@/scripts/event'
import EmailSuggestion from '@/components/EmailSuggestion'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import FileInput from '@/components/FileInput'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent, act } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import $ from 'jquery'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import Pagination from '@/components/Pagination'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import Viewer, { PICTURES_COUNT } from '@/components/Viewer'

View File

@ -1,16 +1,19 @@
/* eslint-disable max-classes-per-file */
import * as fs from 'fs'
import 'jest-extended'
import * as matchers from 'jest-extended'
import '@testing-library/jest-dom'
import yaml from 'js-yaml'
expect.extend(matchers)
window.blessing = {
base_url: '',
locale: 'en',
site_name: 'Blessing Skin',
version: '4.0.0',
extra: {},
i18n: yaml.load(fs.readFileSync('resources/lang/en/front-end.yml', 'utf8')),
i18n: yaml.load(
fs.readFileSync('resources/lang/en/front-end.yml', 'utf8'),
) as object,
}
class Headers extends Map {

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/indent */
import type * as net from '../../src/scripts/net'
export type { ResponseBody } from '../../src/scripts/net'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n'

View File

@ -1,4 +1,3 @@
import React from 'react'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n'

Some files were not shown because too many files have changed in this diff Show More