Skip to content

Commit a0bfb0c

Browse files
authored
Merge pull request #122 from MaaAssistantArknights/dev
feat: UI improvements and fixes
2 parents 248125a + 5731bd4 commit a0bfb0c

File tree

13 files changed

+449
-167
lines changed

13 files changed

+449
-167
lines changed

src/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Effects } from 'components/Effects'
66
import { GlobalErrorBoundary } from './components/GlobalErrorBoundary'
77
import { FCC } from './types'
88
import { request } from './utils/fetcher'
9-
import { localStorageProvider } from './utils/swr-cache'
9+
import { localStorageProvider, swrCacheMiddleware } from './utils/swr-cache'
1010

1111
export const App: FCC = ({ children }) => {
1212
return (
@@ -20,6 +20,7 @@ export const App: FCC = ({ children }) => {
2020
focusThrottleInterval: 1000 * 60,
2121
errorRetryInterval: 1000 * 3,
2222
errorRetryCount: 3,
23+
use: [swrCacheMiddleware],
2324
}}
2425
>
2526
<GlobalErrorBoundary>

src/apis/arknights.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { Level } from 'models/operation'
66

77
import { withoutUnusedLevels } from '../models/level'
88
import { request } from '../utils/fetcher'
9-
import { enableCache } from '../utils/swr-cache'
9+
import { useSWRCache } from '../utils/swr-cache'
1010

1111
const ONE_DAY = 1000 * 60 * 60 * 24
1212

@@ -18,22 +18,25 @@ export const useVersion = () => {
1818

1919
export const useLevels = ({ suspense = true }: { suspense?: boolean } = {}) => {
2020
const url = '/arknights/level'
21+
type LevelResponse = Response<Level[]>
2122

22-
enableCache(
23+
useSWRCache(
2324
url,
2425
// discard the cache if the level data has no stageId
25-
({ data }) =>
26-
!!data?.data && Array.isArray(data.data) && 'stageId' in data.data[0],
26+
({ data }) => {
27+
const firstLevel = (data as LevelResponse)?.data?.[0]
28+
return !!firstLevel && 'stageId' in firstLevel
29+
},
2730
)
2831

29-
const response = useSWR<Response<Level[]>>(url, {
32+
const response = useSWR<LevelResponse>(url, {
3033
focusThrottleInterval: ONE_DAY,
3134
suspense,
3235
fetcher: async (input: string, init?: RequestInit) => {
33-
let res: Response<Level[]>
36+
let res: LevelResponse
3437

3538
try {
36-
res = await request<Response<Level[]>>(input, init)
39+
res = await request<LevelResponse>(input, init)
3740
} catch (e) {
3841
// fallback to built-in levels while retaining the error
3942
res = await requestBuiltInLevels(init)

src/components/AccountManager.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,21 @@ const ActivationInputGroup = <T extends FieldValues>({
121121
})
122122

123123
return (
124-
<InputGroup
125-
large
126-
rightElement={<ActivationCodeRequestButton />}
127-
leftIcon="lock"
128-
onChange={onChange}
129-
onBlur={onBlur}
130-
placeholder="请输入您的激活码"
131-
ref={ref}
132-
className="font-mono"
133-
autoComplete="off"
134-
// eslint-disable-next-line jsx-a11y/no-autofocus
135-
autoFocus
136-
/>
124+
<div className="flex">
125+
<InputGroup
126+
large
127+
leftIcon="lock"
128+
onChange={onChange}
129+
onBlur={onBlur}
130+
placeholder="请输入您的激活码"
131+
ref={ref}
132+
className="flex-grow font-mono"
133+
autoComplete="off"
134+
// eslint-disable-next-line jsx-a11y/no-autofocus
135+
autoFocus
136+
/>
137+
<ActivationCodeRequestButton />
138+
</div>
137139
)
138140
}
139141

src/components/BackToTop.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Button } from '@blueprintjs/core'
2+
3+
import { useEffect, useState } from 'react'
4+
5+
export const BackToTop = () => {
6+
const [showButton, setShowButton] = useState(false)
7+
useEffect(() => {
8+
const handleScroll = () => {
9+
if (window.pageYOffset > 100) {
10+
setShowButton(true)
11+
} else {
12+
setShowButton(false)
13+
}
14+
}
15+
document.addEventListener('scroll', handleScroll)
16+
return () => {
17+
document.removeEventListener('scroll', handleScroll)
18+
}
19+
}, [])
20+
const handleClickButton = () => {
21+
window.scrollTo({ top: 0, behavior: 'smooth' })
22+
}
23+
return (
24+
<div>
25+
{showButton && (
26+
<Button
27+
onClick={handleClickButton}
28+
style={{
29+
position: 'fixed',
30+
bottom: 20,
31+
right: 20,
32+
}}
33+
icon="symbol-triangle-up"
34+
/>
35+
)}
36+
</div>
37+
)
38+
}

src/components/Effects.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useAtom } from 'jotai'
2-
import { FC, useEffect } from 'react'
2+
import { FC, useRef } from 'react'
33

44
import { authAtom, fromCredentials } from 'store/auth'
55
import { FETCHER_CONFIG } from 'utils/fetcher'
@@ -10,8 +10,14 @@ import { AppToaster } from './Toaster'
1010

1111
export const Effects: FC = () => {
1212
const [auth, setAuth] = useAtom(authAtom)
13+
const lastAuth = useRef<typeof auth | null>(null)
14+
15+
// here we are simulating a synchronous version of useEffect(() => {}, [auth])
16+
// in order to set the FETCHER_CONFIG.apiToken before any useSWR() call,
17+
// because useSWR() seems to send request synchronously, and useEffect() is too late
18+
if (lastAuth.current !== auth) {
19+
lastAuth.current = auth
1320

14-
useEffect(() => {
1521
const { token, validBefore, refreshToken, refreshTokenValidBefore } = auth
1622

1723
const endTime = +new Date(validBefore || 0) || 0
@@ -32,7 +38,7 @@ export const Effects: FC = () => {
3238
}
3339

3440
if (!refreshToken) {
35-
// seems that user was logging in in previous version of the app
41+
// the refresh token is somehow missing, no way to update the token
3642
shouldLogout = true
3743
}
3844
}
@@ -66,6 +72,9 @@ export const Effects: FC = () => {
6672
}
6773

6874
if (shouldLogout) {
75+
// FIXME: setting the state synchronously may cause problems (not really sure), so we add a small delay for a temporary hack
76+
await new Promise((resolve) => setTimeout(resolve, 50))
77+
6978
setAuth({})
7079
AppToaster.show({
7180
intent: 'warning',
@@ -84,7 +93,7 @@ export const Effects: FC = () => {
8493
}
8594

8695
FETCHER_CONFIG.apiToken = currentFn
87-
}, [auth])
96+
}
8897

8998
return null
9099
}

src/components/OperationCard.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ const OperatorTags = ({
140140
))}
141141
{groups?.map(({ name, opers }, index) => (
142142
<Tooltip2
143+
key={index}
143144
className="mr-2 last:mr-0 mb-1 last:mb-0"
144145
placement="top"
145146
content={
@@ -148,7 +149,7 @@ const OperatorTags = ({
148149
.join(', ') || '无干员'
149150
}
150151
>
151-
<Tag key={index}>[{name}]</Tag>
152+
<Tag>[{name}]</Tag>
152153
</Tooltip2>
153154
))}
154155
</div>

src/components/entity/EDifficulty.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export const EDifficulty: FC<{
7474
if (difficulty & OpDifficultyBitFlag.REGULAR) {
7575
children.push(
7676
<DifficultyTag
77+
key="regular"
7778
tooltip={descriptions.regular.description}
7879
content={descriptions.regular.title}
7980
/>,
@@ -83,6 +84,7 @@ export const EDifficulty: FC<{
8384
if (difficulty & OpDifficultyBitFlag.HARD) {
8485
children.push(
8586
<DifficultyTag
87+
key="hard"
8688
tooltip={descriptions.hard.description}
8789
content={descriptions.hard.title}
8890
hardLevel

0 commit comments

Comments
 (0)