poi-plugin-quest-info-2 0.5.10 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +1 -1
- package/build/assets.ts +2 -1
- package/build/kcQuestsData/DATA_VERSION +1 -1
- package/build/kcQuestsData/index.ts +1 -1
- package/build/kcQuestsData/quests-scn.json +1123 -1066
- package/build/kcanotifyGamedata/DATA_VERSION +1 -1
- package/build/kcanotifyGamedata/index.ts +1 -1
- package/build/kcanotifyGamedata/quests-en.json +60 -36
- package/build/kcanotifyGamedata/quests-jp.json +506 -482
- package/build/kcanotifyGamedata/quests-ko.json +101 -77
- package/build/kcanotifyGamedata/quests-scn.json +274 -251
- package/build/kcanotifyGamedata/quests-tcn.json +274 -251
- package/build/questCategory.json +600 -0
- package/i18n/en-US.json +4 -2
- package/i18n/ja-JP.json +3 -1
- package/i18n/ko-KR.json +1 -0
- package/i18n/zh-CN.json +3 -1
- package/i18n/zh-TW.json +2 -0
- package/package.json +4 -3
- package/scripts/convertAssets.ts +3 -2
- package/scripts/downloadKcQuestsData.ts +11 -3
- package/scripts/downloadKcanotifyGamedata.ts +10 -2
- package/scripts/genQuestCategory.ts +58 -0
- package/src/Toolbar.tsx +42 -37
- package/src/__tests__/__snapshots__/questCategory.spec.ts.snap +582 -0
- package/src/__tests__/kcanotifyData.spec.ts +1 -1
- package/src/__tests__/kcwikiData.spec.ts +1 -1
- package/src/__tests__/questCategory.spec.ts +37 -0
- package/src/components/PreTaskTag.tsx +40 -0
- package/src/components/QuestCard/MinimalQuestCard.tsx +48 -0
- package/src/components/QuestCard/index.tsx +71 -0
- package/src/components/QuestCard/styles.ts +42 -0
- package/src/components/QuestCard/utils.tsx +68 -0
- package/src/components/QuestList.tsx +2 -1
- package/src/questHelper.ts +24 -18
- package/src/store/filterTags.ts +44 -0
- package/src/store/quest.ts +3 -0
- package/src/store/search.ts +17 -0
- package/src/store/store.tsx +25 -2
- package/src/tags.ts +2 -1
- package/src/components/QuestCard.tsx +0 -213
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Elevation, Text, Tooltip } from '@blueprintjs/core'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { guessQuestCategory, QUEST_STATUS } from '../../questHelper'
|
|
4
|
+
import type { QuestCardProps } from './index'
|
|
5
|
+
import { CardBody, CardTail, CatIndicator, FlexCard } from './styles'
|
|
6
|
+
import { questStatusMap } from './utils'
|
|
7
|
+
|
|
8
|
+
export const MinimalQuestCard: React.FC<QuestCardProps> = ({
|
|
9
|
+
code,
|
|
10
|
+
name,
|
|
11
|
+
desc,
|
|
12
|
+
tips,
|
|
13
|
+
status = QUEST_STATUS.DEFAULT,
|
|
14
|
+
onClick,
|
|
15
|
+
style,
|
|
16
|
+
}) => {
|
|
17
|
+
const indicatorColor = guessQuestCategory(code).color
|
|
18
|
+
const TailIcon = questStatusMap[status]
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Tooltip
|
|
22
|
+
targetTagName="div"
|
|
23
|
+
content={
|
|
24
|
+
<>
|
|
25
|
+
{desc}
|
|
26
|
+
<br />
|
|
27
|
+
{tips}
|
|
28
|
+
</>
|
|
29
|
+
}
|
|
30
|
+
>
|
|
31
|
+
<FlexCard
|
|
32
|
+
elevation={Elevation.ZERO}
|
|
33
|
+
interactive={true}
|
|
34
|
+
onClick={onClick}
|
|
35
|
+
style={style}
|
|
36
|
+
>
|
|
37
|
+
<CatIndicator color={indicatorColor}></CatIndicator>
|
|
38
|
+
<CardBody>
|
|
39
|
+
<Text>{[code, name].filter((i) => i != undefined).join(' - ')}</Text>
|
|
40
|
+
</CardBody>
|
|
41
|
+
|
|
42
|
+
<CardTail>
|
|
43
|
+
<TailIcon></TailIcon>
|
|
44
|
+
</CardTail>
|
|
45
|
+
</FlexCard>
|
|
46
|
+
</Tooltip>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Elevation, H5, Text } from '@blueprintjs/core'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import styled from 'styled-components'
|
|
4
|
+
import { usePluginTranslation } from '../../poi/hooks'
|
|
5
|
+
import { guessQuestCategory, QUEST_STATUS } from '../../questHelper'
|
|
6
|
+
import { PreTaskTag } from '../PreTaskTag'
|
|
7
|
+
import { CardBody, CardMedia, CardTail, FlexCard } from './styles'
|
|
8
|
+
import { questIconMap, questStatusMap } from './utils'
|
|
9
|
+
|
|
10
|
+
export type QuestCardProps = {
|
|
11
|
+
code: string
|
|
12
|
+
name: string
|
|
13
|
+
desc: string | JSX.Element
|
|
14
|
+
tips?: string
|
|
15
|
+
status?: QUEST_STATUS
|
|
16
|
+
preTask?: string[]
|
|
17
|
+
onClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
|
|
18
|
+
style?: React.CSSProperties
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const PreTaskTagWrapper = styled.div`
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: baseline;
|
|
24
|
+
`
|
|
25
|
+
|
|
26
|
+
export const LargeQuestCard = ({
|
|
27
|
+
code,
|
|
28
|
+
name,
|
|
29
|
+
desc,
|
|
30
|
+
tips,
|
|
31
|
+
preTask,
|
|
32
|
+
status = QUEST_STATUS.DEFAULT,
|
|
33
|
+
onClick,
|
|
34
|
+
style,
|
|
35
|
+
}: QuestCardProps) => {
|
|
36
|
+
const headIcon = questIconMap[guessQuestCategory(code).type]
|
|
37
|
+
const TailIcon = questStatusMap[status]
|
|
38
|
+
const { t } = usePluginTranslation()
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<FlexCard
|
|
42
|
+
elevation={Elevation.ZERO}
|
|
43
|
+
interactive={false}
|
|
44
|
+
onClick={onClick}
|
|
45
|
+
style={style}
|
|
46
|
+
>
|
|
47
|
+
<CardMedia src={headIcon}></CardMedia>
|
|
48
|
+
<CardBody>
|
|
49
|
+
<H5>{[code, name].filter((i) => i != undefined).join(' - ')}</H5>
|
|
50
|
+
<Text>{desc}</Text>
|
|
51
|
+
{tips && <Text tagName="i">{tips}</Text>}
|
|
52
|
+
<PreTaskTagWrapper>
|
|
53
|
+
{!!preTask?.length && <Text tagName="span">{t('Requires')}</Text>}
|
|
54
|
+
{preTask?.map((i) => (
|
|
55
|
+
<PreTaskTag key={i} code={i}></PreTaskTag>
|
|
56
|
+
))}
|
|
57
|
+
</PreTaskTagWrapper>
|
|
58
|
+
</CardBody>
|
|
59
|
+
|
|
60
|
+
<CardTail>
|
|
61
|
+
<TailIcon />
|
|
62
|
+
</CardTail>
|
|
63
|
+
</FlexCard>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const QuestCard: React.FC<QuestCardProps & { gameId: string }> = ({
|
|
68
|
+
...props
|
|
69
|
+
}) => {
|
|
70
|
+
return <LargeQuestCard {...props}></LargeQuestCard>
|
|
71
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Card } from '@blueprintjs/core'
|
|
2
|
+
import styled from 'styled-components'
|
|
3
|
+
|
|
4
|
+
export const FlexCard = styled(Card)`
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
|
|
8
|
+
& > * + * {
|
|
9
|
+
margin-left: 8px;
|
|
10
|
+
}
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
export const CardMedia = styled.img`
|
|
14
|
+
width: 64px;
|
|
15
|
+
height: 64px;
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
export const CatIndicator = styled.span<{ color: string }>`
|
|
19
|
+
height: 1em;
|
|
20
|
+
width: 4px;
|
|
21
|
+
background-color: ${({ color }) => color};
|
|
22
|
+
`
|
|
23
|
+
|
|
24
|
+
export const CardBody = styled.div`
|
|
25
|
+
display: flex;
|
|
26
|
+
flex: 1;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
|
|
29
|
+
& > * + * {
|
|
30
|
+
margin-top: 8px;
|
|
31
|
+
}
|
|
32
|
+
`
|
|
33
|
+
|
|
34
|
+
export const CardTail = styled.div`
|
|
35
|
+
display: flex;
|
|
36
|
+
justify-content: center;
|
|
37
|
+
align-items: center;
|
|
38
|
+
|
|
39
|
+
img {
|
|
40
|
+
height: 20px;
|
|
41
|
+
}
|
|
42
|
+
`
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Icon, Tooltip } from '@blueprintjs/core'
|
|
2
|
+
import { IconNames } from '@blueprintjs/icons'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import {
|
|
5
|
+
IconArsenal,
|
|
6
|
+
IconCompleted,
|
|
7
|
+
IconComposition,
|
|
8
|
+
IconExercise,
|
|
9
|
+
IconExpedition,
|
|
10
|
+
IconInProgress,
|
|
11
|
+
IconModernization,
|
|
12
|
+
IconSortie,
|
|
13
|
+
IconSupplyDocking,
|
|
14
|
+
} from '../../../build/assets'
|
|
15
|
+
import { usePluginTranslation } from '../../poi/hooks'
|
|
16
|
+
import { QUEST_CATEGORY, QUEST_STATUS } from '../../questHelper'
|
|
17
|
+
|
|
18
|
+
export const questStatusMap: Record<QUEST_STATUS, React.FC> = {
|
|
19
|
+
[QUEST_STATUS.LOCKED]: function Locked() {
|
|
20
|
+
const { t } = usePluginTranslation()
|
|
21
|
+
return (
|
|
22
|
+
<Tooltip content={t('Locked')}>
|
|
23
|
+
<Icon icon={IconNames.LOCK} iconSize={Icon.SIZE_LARGE}></Icon>
|
|
24
|
+
</Tooltip>
|
|
25
|
+
)
|
|
26
|
+
},
|
|
27
|
+
// Display nothing
|
|
28
|
+
[QUEST_STATUS.DEFAULT]: () => null,
|
|
29
|
+
[QUEST_STATUS.IN_PROGRESS]: function InProgress() {
|
|
30
|
+
const { t } = usePluginTranslation()
|
|
31
|
+
return (
|
|
32
|
+
<Tooltip content={t('In Progress')}>
|
|
33
|
+
<img src={IconInProgress}></img>
|
|
34
|
+
</Tooltip>
|
|
35
|
+
)
|
|
36
|
+
},
|
|
37
|
+
[QUEST_STATUS.COMPLETED]: function Completed() {
|
|
38
|
+
const { t } = usePluginTranslation()
|
|
39
|
+
return (
|
|
40
|
+
<Tooltip content={t('Completed')}>
|
|
41
|
+
<img src={IconCompleted}></img>
|
|
42
|
+
</Tooltip>
|
|
43
|
+
)
|
|
44
|
+
},
|
|
45
|
+
[QUEST_STATUS.ALREADY_COMPLETED]: function AlreadyCompleted() {
|
|
46
|
+
const { t } = usePluginTranslation()
|
|
47
|
+
return (
|
|
48
|
+
<Tooltip content={t('Already Completed')}>
|
|
49
|
+
<Icon icon={IconNames.TICK} iconSize={Icon.SIZE_LARGE}></Icon>
|
|
50
|
+
</Tooltip>
|
|
51
|
+
)
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// transparent GIF pixel
|
|
56
|
+
const PLACEHOLDER =
|
|
57
|
+
'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
|
|
58
|
+
|
|
59
|
+
export const questIconMap = {
|
|
60
|
+
[QUEST_CATEGORY.Composition]: IconComposition,
|
|
61
|
+
[QUEST_CATEGORY.Sortie]: IconSortie,
|
|
62
|
+
[QUEST_CATEGORY.Exercise]: IconExercise,
|
|
63
|
+
[QUEST_CATEGORY.Expedition]: IconExpedition,
|
|
64
|
+
[QUEST_CATEGORY.SupplyOrDocking]: IconSupplyDocking,
|
|
65
|
+
[QUEST_CATEGORY.Arsenal]: IconArsenal,
|
|
66
|
+
[QUEST_CATEGORY.Modernization]: IconModernization,
|
|
67
|
+
[QUEST_CATEGORY.Unknown]: PLACEHOLDER,
|
|
68
|
+
} as const
|
|
@@ -47,7 +47,7 @@ const useQuestsRowRenderer = (quests: UnionQuest[]) => {
|
|
|
47
47
|
({ key, index, style, parent }: ListRowProps) => {
|
|
48
48
|
const quest = quests[index]
|
|
49
49
|
const { gameId } = quest
|
|
50
|
-
const { code, name, desc, memo } = quest.docQuest
|
|
50
|
+
const { code, name, desc, memo, pre } = quest.docQuest
|
|
51
51
|
const questStatus = questStateToQuestStatus(quest.gameQuest?.api_state)
|
|
52
52
|
|
|
53
53
|
return (
|
|
@@ -66,6 +66,7 @@ const useQuestsRowRenderer = (quests: UnionQuest[]) => {
|
|
|
66
66
|
name={name}
|
|
67
67
|
desc={desc}
|
|
68
68
|
tips={memo}
|
|
69
|
+
preTask={pre}
|
|
69
70
|
status={questStatus}
|
|
70
71
|
></QuestCard>
|
|
71
72
|
</div>
|
package/src/questHelper.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import questCategory from '../build/questCategory.json'
|
|
2
2
|
import { GameQuest, QUEST_API_STATE } from './poi/types'
|
|
3
3
|
|
|
4
4
|
type DocQuest = {
|
|
@@ -6,8 +6,18 @@ type DocQuest = {
|
|
|
6
6
|
name: string
|
|
7
7
|
desc: string
|
|
8
8
|
memo?: string
|
|
9
|
+
/**
|
|
10
|
+
* Only in kcanotify
|
|
11
|
+
*/
|
|
9
12
|
unlock?: number[]
|
|
13
|
+
/**
|
|
14
|
+
* Only in kcanotify
|
|
15
|
+
*/
|
|
10
16
|
tracking?: number[][]
|
|
17
|
+
/**
|
|
18
|
+
* Only in KcWiki
|
|
19
|
+
*/
|
|
20
|
+
pre?: string[]
|
|
11
21
|
}
|
|
12
22
|
|
|
13
23
|
export type UnionQuest = {
|
|
@@ -16,31 +26,27 @@ export type UnionQuest = {
|
|
|
16
26
|
docQuest: DocQuest
|
|
17
27
|
}
|
|
18
28
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export const weeklyQuest = questStartsFilter('(周任)')
|
|
26
|
-
export const monthlyQuest = questStartsFilter('(月任)')
|
|
27
|
-
export const quarterlyQuest = questStartsFilter('(季任)')
|
|
28
|
-
// (年任) (年任 / x 月)
|
|
29
|
-
export const yearlyQuest = questStartsFilter('(年任')
|
|
29
|
+
const dailyQuest = new Set(questCategory.dailyQuest)
|
|
30
|
+
const weeklyQuest = new Set(questCategory.weeklyQuest)
|
|
31
|
+
const monthlyQuest = new Set(questCategory.monthlyQuest)
|
|
32
|
+
const quarterlyQuest = new Set(questCategory.quarterlyQuest)
|
|
33
|
+
const yearlyQuest = new Set(questCategory.yearlyQuest)
|
|
34
|
+
const singleQuest = new Set(questCategory.singleQuest)
|
|
30
35
|
|
|
31
36
|
export const isInProgressQuest = (quest: UnionQuest) =>
|
|
32
37
|
quest.gameQuest?.api_state === QUEST_API_STATE.IN_PROGRESS ||
|
|
33
38
|
quest.gameQuest?.api_state === QUEST_API_STATE.COMPLETED
|
|
34
|
-
export const isDailyQuest = (quest: UnionQuest) =>
|
|
35
|
-
dailyQuest.includes(quest.gameId)
|
|
39
|
+
export const isDailyQuest = (quest: UnionQuest) => dailyQuest.has(quest.gameId)
|
|
36
40
|
export const isWeeklyQuest = (quest: UnionQuest) =>
|
|
37
|
-
weeklyQuest.
|
|
41
|
+
weeklyQuest.has(quest.gameId)
|
|
38
42
|
export const isMonthlyQuest = (quest: UnionQuest) =>
|
|
39
|
-
monthlyQuest.
|
|
43
|
+
monthlyQuest.has(quest.gameId)
|
|
40
44
|
export const isQuarterlyQuest = (quest: UnionQuest) =>
|
|
41
|
-
quarterlyQuest.
|
|
45
|
+
quarterlyQuest.has(quest.gameId)
|
|
42
46
|
export const isYearlyQuest = (quest: UnionQuest) =>
|
|
43
|
-
yearlyQuest.
|
|
47
|
+
yearlyQuest.has(quest.gameId)
|
|
48
|
+
export const isSingleQuest = (quest: UnionQuest) =>
|
|
49
|
+
singleQuest.has(quest.gameId)
|
|
44
50
|
|
|
45
51
|
export enum QUEST_CATEGORY {
|
|
46
52
|
Composition = '1',
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
ALL_CATEGORY_TAG,
|
|
4
|
+
ALL_TYPE_TAG,
|
|
5
|
+
CATEGORY_TAGS,
|
|
6
|
+
TYPE_TAGS,
|
|
7
|
+
} from '../tags'
|
|
8
|
+
import { useStore } from './store'
|
|
9
|
+
|
|
10
|
+
export const useFilterTags = () => {
|
|
11
|
+
const {
|
|
12
|
+
store: { categoryTags, typeTags },
|
|
13
|
+
updateStore,
|
|
14
|
+
} = useStore()
|
|
15
|
+
const setCategoryTags = useCallback(
|
|
16
|
+
(tagName: typeof CATEGORY_TAGS[number]['name']) => {
|
|
17
|
+
updateStore({ categoryTags: { [tagName]: true } })
|
|
18
|
+
},
|
|
19
|
+
[updateStore]
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const setCategoryTagsAll = useCallback(() => {
|
|
23
|
+
setCategoryTags(ALL_CATEGORY_TAG.name)
|
|
24
|
+
}, [setCategoryTags])
|
|
25
|
+
|
|
26
|
+
const setTypeTags = useCallback(
|
|
27
|
+
(tagName: typeof TYPE_TAGS[number]['name']) => {
|
|
28
|
+
updateStore({ typeTags: { [tagName]: true } })
|
|
29
|
+
},
|
|
30
|
+
[updateStore]
|
|
31
|
+
)
|
|
32
|
+
const setTypeTagsAll = useCallback(() => {
|
|
33
|
+
setTypeTags(ALL_TYPE_TAG.name)
|
|
34
|
+
}, [setTypeTags])
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
categoryTags,
|
|
38
|
+
typeTags,
|
|
39
|
+
setCategoryTags,
|
|
40
|
+
setCategoryTagsAll,
|
|
41
|
+
setTypeTags,
|
|
42
|
+
setTypeTagsAll,
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/store/quest.ts
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
import { useStore } from './store'
|
|
3
|
+
|
|
4
|
+
export const useSearchInput = () => {
|
|
5
|
+
const {
|
|
6
|
+
store: { searchInput },
|
|
7
|
+
updateStore,
|
|
8
|
+
} = useStore()
|
|
9
|
+
const setSearchInput = useCallback(
|
|
10
|
+
(value: string) => updateStore({ searchInput: value }),
|
|
11
|
+
[updateStore]
|
|
12
|
+
)
|
|
13
|
+
return {
|
|
14
|
+
searchInput,
|
|
15
|
+
setSearchInput,
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/store/store.tsx
CHANGED
|
@@ -78,9 +78,12 @@ export const useStore = () => {
|
|
|
78
78
|
const store = useContext(StateContext)
|
|
79
79
|
const setStore = useContext(SetStateContext)
|
|
80
80
|
const updateStore = useCallback(
|
|
81
|
-
(newStore: Partial<State>) =>
|
|
82
|
-
|
|
81
|
+
(newStore: Partial<State>) => {
|
|
82
|
+
setStore((previousStore) => ({ ...previousStore, ...newStore }))
|
|
83
|
+
},
|
|
84
|
+
[setStore]
|
|
83
85
|
)
|
|
86
|
+
|
|
84
87
|
return { store, setStore, updateStore }
|
|
85
88
|
}
|
|
86
89
|
|
|
@@ -91,3 +94,23 @@ export const useRemoveStorage = () => {
|
|
|
91
94
|
updateStore(initialState)
|
|
92
95
|
}
|
|
93
96
|
}
|
|
97
|
+
|
|
98
|
+
export const useSyncWithGame = () => {
|
|
99
|
+
const {
|
|
100
|
+
store: { syncWithGame },
|
|
101
|
+
updateStore,
|
|
102
|
+
} = useStore()
|
|
103
|
+
const setSyncWithGame = useCallback(
|
|
104
|
+
(value: boolean) => {
|
|
105
|
+
updateStore({ syncWithGame: value })
|
|
106
|
+
},
|
|
107
|
+
[updateStore]
|
|
108
|
+
)
|
|
109
|
+
const toggleSyncWithGame = useCallback(() => {
|
|
110
|
+
setSyncWithGame(!syncWithGame)
|
|
111
|
+
}, [setSyncWithGame, syncWithGame])
|
|
112
|
+
return {
|
|
113
|
+
syncWithGame,
|
|
114
|
+
toggleSyncWithGame,
|
|
115
|
+
}
|
|
116
|
+
}
|
package/src/tags.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
isModernizationQuest,
|
|
15
15
|
isUnknownCategoryQuest,
|
|
16
16
|
isInProgressQuest,
|
|
17
|
+
isSingleQuest,
|
|
17
18
|
} from './questHelper'
|
|
18
19
|
import type { UnionQuest } from './questHelper'
|
|
19
20
|
|
|
@@ -51,7 +52,7 @@ export const TYPE_TAGS = [
|
|
|
51
52
|
{ name: 'Monthly', filter: isMonthlyQuest },
|
|
52
53
|
{ name: 'Quarterly', filter: isQuarterlyQuest },
|
|
53
54
|
{ name: 'Yearly', filter: isYearlyQuest },
|
|
54
|
-
|
|
55
|
+
{ name: 'One-time', filter: isSingleQuest },
|
|
55
56
|
] as const
|
|
56
57
|
|
|
57
58
|
// TODO tag In Progress / Lock / Completed
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { Card, Elevation, H5, Text, Tooltip, Icon } from '@blueprintjs/core'
|
|
2
|
-
import { IconNames } from '@blueprintjs/icons'
|
|
3
|
-
import React, { useCallback } from 'react'
|
|
4
|
-
import styled from 'styled-components'
|
|
5
|
-
import { usePluginTranslation } from '../poi/hooks'
|
|
6
|
-
import {
|
|
7
|
-
guessQuestCategory,
|
|
8
|
-
QUEST_CATEGORY,
|
|
9
|
-
QUEST_STATUS,
|
|
10
|
-
} from '../questHelper'
|
|
11
|
-
import { IconComposition } from '../../build/assets'
|
|
12
|
-
import { IconExpedition } from '../../build/assets'
|
|
13
|
-
import { IconArsenal } from '../../build/assets'
|
|
14
|
-
import { IconModernization } from '../../build/assets'
|
|
15
|
-
import { IconExercise } from '../../build/assets'
|
|
16
|
-
import { IconSortie } from '../../build/assets'
|
|
17
|
-
import { IconSupplyDocking } from '../../build/assets'
|
|
18
|
-
import { IconInProgress } from '../../build/assets'
|
|
19
|
-
import { IconCompleted } from '../../build/assets'
|
|
20
|
-
import { useLargeCard } from '../store/quest'
|
|
21
|
-
|
|
22
|
-
const FlexCard = styled(Card)`
|
|
23
|
-
display: flex;
|
|
24
|
-
align-items: center;
|
|
25
|
-
|
|
26
|
-
& > * + * {
|
|
27
|
-
margin-left: 8px;
|
|
28
|
-
}
|
|
29
|
-
`
|
|
30
|
-
|
|
31
|
-
const CardMedia = styled.img`
|
|
32
|
-
width: 64px;
|
|
33
|
-
height: 64px;
|
|
34
|
-
`
|
|
35
|
-
|
|
36
|
-
const CatIndicator = styled.span<{ color: string }>`
|
|
37
|
-
height: 1em;
|
|
38
|
-
width: 4px;
|
|
39
|
-
background-color: ${({ color }) => color};
|
|
40
|
-
`
|
|
41
|
-
|
|
42
|
-
const CardBody = styled.div`
|
|
43
|
-
display: flex;
|
|
44
|
-
flex: 1;
|
|
45
|
-
flex-direction: column;
|
|
46
|
-
|
|
47
|
-
* + * {
|
|
48
|
-
margin-top: 8px;
|
|
49
|
-
}
|
|
50
|
-
`
|
|
51
|
-
|
|
52
|
-
const CardTail = styled.div`
|
|
53
|
-
display: flex;
|
|
54
|
-
justify-content: center;
|
|
55
|
-
align-items: center;
|
|
56
|
-
|
|
57
|
-
img {
|
|
58
|
-
height: 20px;
|
|
59
|
-
}
|
|
60
|
-
`
|
|
61
|
-
|
|
62
|
-
// transparent GIF pixel
|
|
63
|
-
const PLACEHOLDER =
|
|
64
|
-
'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
|
|
65
|
-
|
|
66
|
-
const questIconMap = {
|
|
67
|
-
[QUEST_CATEGORY.Composition]: IconComposition,
|
|
68
|
-
[QUEST_CATEGORY.Sortie]: IconSortie,
|
|
69
|
-
[QUEST_CATEGORY.Exercise]: IconExercise,
|
|
70
|
-
[QUEST_CATEGORY.Expedition]: IconExpedition,
|
|
71
|
-
[QUEST_CATEGORY.SupplyOrDocking]: IconSupplyDocking,
|
|
72
|
-
[QUEST_CATEGORY.Arsenal]: IconArsenal,
|
|
73
|
-
[QUEST_CATEGORY.Modernization]: IconModernization,
|
|
74
|
-
[QUEST_CATEGORY.Unknown]: PLACEHOLDER,
|
|
75
|
-
} as const
|
|
76
|
-
|
|
77
|
-
const questStatusMap: Record<QUEST_STATUS, React.FC> = {
|
|
78
|
-
[QUEST_STATUS.LOCKED]: function Locked() {
|
|
79
|
-
const { t } = usePluginTranslation()
|
|
80
|
-
return (
|
|
81
|
-
<Tooltip content={t('Locked')}>
|
|
82
|
-
<Icon icon={IconNames.LOCK} iconSize={Icon.SIZE_LARGE}></Icon>
|
|
83
|
-
</Tooltip>
|
|
84
|
-
)
|
|
85
|
-
},
|
|
86
|
-
// Display nothing
|
|
87
|
-
[QUEST_STATUS.DEFAULT]: () => null,
|
|
88
|
-
[QUEST_STATUS.IN_PROGRESS]: function InProgress() {
|
|
89
|
-
const { t } = usePluginTranslation()
|
|
90
|
-
return (
|
|
91
|
-
<Tooltip content={t('In Progress')}>
|
|
92
|
-
<img src={IconInProgress}></img>
|
|
93
|
-
</Tooltip>
|
|
94
|
-
)
|
|
95
|
-
},
|
|
96
|
-
[QUEST_STATUS.COMPLETED]: function Completed() {
|
|
97
|
-
const { t } = usePluginTranslation()
|
|
98
|
-
return (
|
|
99
|
-
<Tooltip content={t('Completed')}>
|
|
100
|
-
<img src={IconCompleted}></img>
|
|
101
|
-
</Tooltip>
|
|
102
|
-
)
|
|
103
|
-
},
|
|
104
|
-
[QUEST_STATUS.ALREADY_COMPLETED]: function AlreadyCompleted() {
|
|
105
|
-
const { t } = usePluginTranslation()
|
|
106
|
-
return (
|
|
107
|
-
<Tooltip content={t('Already Completed')}>
|
|
108
|
-
<Icon icon={IconNames.TICK} iconSize={Icon.SIZE_LARGE}></Icon>
|
|
109
|
-
</Tooltip>
|
|
110
|
-
)
|
|
111
|
-
},
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
type QuestCardProps = {
|
|
115
|
-
code: string
|
|
116
|
-
name: string
|
|
117
|
-
desc: string | JSX.Element
|
|
118
|
-
tips?: string
|
|
119
|
-
status?: QUEST_STATUS
|
|
120
|
-
onClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
|
|
121
|
-
style?: React.CSSProperties
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export const LargeQuestCard: React.FC<QuestCardProps> = ({
|
|
125
|
-
code,
|
|
126
|
-
name,
|
|
127
|
-
desc,
|
|
128
|
-
tips,
|
|
129
|
-
status = QUEST_STATUS.DEFAULT,
|
|
130
|
-
onClick,
|
|
131
|
-
style,
|
|
132
|
-
}) => {
|
|
133
|
-
const headIcon = questIconMap[guessQuestCategory(code).type]
|
|
134
|
-
const TailIcon = questStatusMap[status]
|
|
135
|
-
|
|
136
|
-
return (
|
|
137
|
-
<FlexCard
|
|
138
|
-
elevation={Elevation.ZERO}
|
|
139
|
-
interactive={true}
|
|
140
|
-
onClick={onClick}
|
|
141
|
-
style={style}
|
|
142
|
-
>
|
|
143
|
-
<CardMedia src={headIcon}></CardMedia>
|
|
144
|
-
<CardBody>
|
|
145
|
-
<H5>{[code, name].filter((i) => i != undefined).join(' - ')}</H5>
|
|
146
|
-
<Text>{desc}</Text>
|
|
147
|
-
<Text tagName="i">{tips}</Text>
|
|
148
|
-
</CardBody>
|
|
149
|
-
|
|
150
|
-
<CardTail>
|
|
151
|
-
<TailIcon></TailIcon>
|
|
152
|
-
</CardTail>
|
|
153
|
-
</FlexCard>
|
|
154
|
-
)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export const MinimalQuestCard: React.FC<QuestCardProps> = ({
|
|
158
|
-
code,
|
|
159
|
-
name,
|
|
160
|
-
desc,
|
|
161
|
-
tips,
|
|
162
|
-
status = QUEST_STATUS.DEFAULT,
|
|
163
|
-
onClick,
|
|
164
|
-
style,
|
|
165
|
-
}) => {
|
|
166
|
-
const indicatorColor = guessQuestCategory(code).color
|
|
167
|
-
const TailIcon = questStatusMap[status]
|
|
168
|
-
|
|
169
|
-
return (
|
|
170
|
-
<Tooltip
|
|
171
|
-
targetTagName="div"
|
|
172
|
-
content={
|
|
173
|
-
<>
|
|
174
|
-
{desc}
|
|
175
|
-
<br />
|
|
176
|
-
{tips}
|
|
177
|
-
</>
|
|
178
|
-
}
|
|
179
|
-
>
|
|
180
|
-
<FlexCard
|
|
181
|
-
elevation={Elevation.ZERO}
|
|
182
|
-
interactive={true}
|
|
183
|
-
onClick={onClick}
|
|
184
|
-
style={style}
|
|
185
|
-
>
|
|
186
|
-
<CatIndicator color={indicatorColor}></CatIndicator>
|
|
187
|
-
<CardBody>
|
|
188
|
-
<Text>{[code, name].filter((i) => i != undefined).join(' - ')}</Text>
|
|
189
|
-
</CardBody>
|
|
190
|
-
|
|
191
|
-
<CardTail>
|
|
192
|
-
<TailIcon></TailIcon>
|
|
193
|
-
</CardTail>
|
|
194
|
-
</FlexCard>
|
|
195
|
-
</Tooltip>
|
|
196
|
-
)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export const QuestCard: React.FC<QuestCardProps & { gameId: string }> = ({
|
|
200
|
-
gameId,
|
|
201
|
-
...props
|
|
202
|
-
}) => {
|
|
203
|
-
const { largeCard, setLarge, setMinimal } = useLargeCard()
|
|
204
|
-
const setQuestCardLarge = useCallback(
|
|
205
|
-
() => setLarge(gameId),
|
|
206
|
-
[gameId, setLarge]
|
|
207
|
-
)
|
|
208
|
-
return gameId === largeCard ? (
|
|
209
|
-
<LargeQuestCard onClick={setMinimal} {...props}></LargeQuestCard>
|
|
210
|
-
) : (
|
|
211
|
-
<MinimalQuestCard onClick={setQuestCardLarge} {...props}></MinimalQuestCard>
|
|
212
|
-
)
|
|
213
|
-
}
|