Skip to content

Commit fe9c6b3

Browse files
authored
Release to Production (#438)
> *This PR is automatically created by actions defined in this repository. To see the run log of this action, please click [here](/ZOOT-Plus/zoot-plus-frontend/actions/runs/15456190324)*
2 parents 04d1be4 + c487297 commit fe9c6b3

File tree

10 files changed

+335
-30
lines changed

10 files changed

+335
-30
lines changed

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
## 2025-05-27
1+
## 2025-06-05
2+
3+
- 优化了编辑器v2中的干员列表 [@Gemini2035](https://github.com/Gemini2035)
4+
- 修复了编辑器v2中部署方向在暗色模式下显示不正常的问题 [@czgaotian](https://github.com/czgaotian)
5+
- 修复了首页的作业列表未显示操作按钮的问题 [@guansss](https://github.com/guansss)
6+
- 广告更新
7+
8+
## 2025-06-04
29

310
- 修复了编辑器v2中修改难度后不显示的问题 [@guansss](https://github.com/guansss)
411
- 修复了编辑器v2中从自动保存恢复后显示不正常的问题 [@guansss](https://github.com/guansss)

public/ad_leidian.jpg

-404 KB
Binary file not shown.

public/ad_leidian.webp

45.4 KB
Loading

src/components/OperationCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ export const OperationCard = ({ operation }: { operation: Operation }) => {
152152
const { data: levels } = useLevels()
153153

154154
return (
155-
<li className="mb-4 sm:mb-2 last:mb-0">
155+
<li className="mb-4 sm:mb-2 last:mb-0 relative">
156156
<ReLinkRenderer
157157
search={{ op: operation.id }}
158158
render={({ onClick, onKeyDown }) => (

src/components/editor/operator/sheet/sheetOperator/toolBox/OperatorBackToTop.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const OperatorBackToTop: FC<OperatorBackToTopProp> = ({ toTop }) => {
2222
<Button
2323
minimal
2424
icon="symbol-triangle-up"
25-
disabled={current < 3}
25+
disabled={current < 2}
2626
title={
2727
t.components.editor.operator.sheet.sheetOperator.toolbox
2828
.OperatorBackToTop.back_to_top

src/components/editor/operator/sheet/sheetOperator/toolBox/OperatorRaritySelect.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
useOperatorFilterProvider,
1111
} from '../SheetOperatorFilterProvider'
1212

13+
const selectClass = 'scale-90'
14+
1315
export interface OperatorRaritySelectProp {}
1416

1517
export const OperatorRaritySelect: FC<OperatorRaritySelectProp> = () => {
@@ -18,8 +20,6 @@ export const OperatorRaritySelect: FC<OperatorRaritySelectProp> = () => {
1820
useRarityFilterState: [{ selectedRarity, reverse }, setRarityFilter],
1921
} = useOperatorFilterProvider()
2022

21-
const selectClass = 'scale-90'
22-
2323
return (
2424
<>
2525
<div className="flex items-center">

src/components/editor2/action/ActionItem.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export const ActionItem: FC<ActionItemProps> = memo(
107107
typeInfo.accentText,
108108
)}
109109
>
110-
<div className="flex flex-wrap items-center">
110+
<div className="flex flex-wrap items-center !text-inherit">
111111
<h4
112112
className={clsx(
113113
'relative shrink-0 self-stretch w-[5em] text-2xl font-serif bg-gray-100 dark:bg-gray-700 cursor-move select-none touch-manipulation',
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import { Divider, H4, H5, Icon } from '@blueprintjs/core'
2+
3+
import clsx from 'clsx'
4+
import { languageAtom, useTranslation } from 'i18n/i18n'
5+
import { useAtomValue } from 'jotai'
6+
import {
7+
FC,
8+
HTMLAttributes,
9+
ImgHTMLAttributes,
10+
useEffect,
11+
useMemo,
12+
useRef,
13+
useState,
14+
} from 'react'
15+
16+
import {
17+
DEFAULTPROFID,
18+
DEFAULTSUBPROFID,
19+
useOperatorFilterProvider,
20+
} from 'components/editor/operator/sheet/sheetOperator/SheetOperatorFilterProvider'
21+
import { PROFESSIONS } from 'models/operator'
22+
23+
export interface ProfClassification {}
24+
25+
export const ProfClassification: FC<ProfClassification> = () => {
26+
const t = useTranslation()
27+
const language = useAtomValue(languageAtom)
28+
const {
29+
useProfFilterState: [{ selectedProf }, setProfFilter],
30+
} = useOperatorFilterProvider()
31+
32+
const formattedProfessions = useMemo(
33+
() => [
34+
{
35+
id: DEFAULTPROFID.ALL,
36+
name: t.components.editor.operator.sheet.sheetOperator
37+
.ProfClassificationWithFilters.all,
38+
name_en:
39+
t.components.editor.operator.sheet.sheetOperator
40+
.ProfClassificationWithFilters.all,
41+
sub: [],
42+
},
43+
{
44+
id: DEFAULTPROFID.FAV,
45+
name: t.components.editor.operator.sheet.sheetOperator
46+
.ProfClassificationWithFilters.favorites,
47+
name_en:
48+
t.components.editor.operator.sheet.sheetOperator
49+
.ProfClassificationWithFilters.favorites,
50+
sub: [],
51+
},
52+
...PROFESSIONS.map((profession) => ({
53+
...profession,
54+
name_en: profession.name_en || profession.name,
55+
})),
56+
{
57+
id: DEFAULTPROFID.OTHERS,
58+
name: t.components.editor.operator.sheet.sheetOperator
59+
.ProfClassificationWithFilters.others,
60+
name_en:
61+
t.components.editor.operator.sheet.sheetOperator
62+
.ProfClassificationWithFilters.others,
63+
sub: [],
64+
},
65+
],
66+
[t],
67+
)
68+
const subProfs = useMemo(() => {
69+
return [
70+
{
71+
id: DEFAULTSUBPROFID.ALL,
72+
name: t.components.editor.operator.sheet.sheetOperator
73+
.ProfClassificationWithFilters.all,
74+
name_en:
75+
t.components.editor.operator.sheet.sheetOperator
76+
.ProfClassificationWithFilters.all,
77+
},
78+
{
79+
id: DEFAULTSUBPROFID.SELECTED,
80+
name: t.components.editor.operator.sheet.sheetOperator
81+
.ProfClassificationWithFilters.selected,
82+
name_en:
83+
t.components.editor.operator.sheet.sheetOperator
84+
.ProfClassificationWithFilters.selected,
85+
},
86+
...(formattedProfessions.find(({ id }) => id === selectedProf[0])?.sub ||
87+
[]),
88+
]
89+
}, [selectedProf, formattedProfessions, t])
90+
91+
return (
92+
<div>
93+
<UlWithArrow className="px-4 py-2 gap-4 " key={selectedProf[0]}>
94+
{subProfs.map((subProf) => (
95+
<li key={subProf.id} className="flex items-center justify-center">
96+
<H4
97+
className={clsx(
98+
'truncate cursor-pointer opacity-50 hover:underline hover:opacity-90 m-0',
99+
selectedProf.includes(subProf.id) && '!opacity-100 underline',
100+
)}
101+
onClick={() =>
102+
setProfFilter(({ selectedProf, ...rest }) => ({
103+
selectedProf: [selectedProf[0], subProf.id],
104+
...rest,
105+
}))
106+
}
107+
>
108+
{language === 'en' && subProf.name_en
109+
? subProf.name_en
110+
: subProf.name}
111+
</H4>
112+
</li>
113+
))}
114+
</UlWithArrow>
115+
<Divider className="m-0" />
116+
<UlWithArrow className="py-1">
117+
{formattedProfessions.map((prof) => (
118+
<ProfIcon
119+
key={prof.id}
120+
profId={prof.id}
121+
name={language === 'en' && prof.name_en ? prof.name_en : prof.name}
122+
selected={selectedProf.includes(prof.id)}
123+
onProfClick={() =>
124+
setProfFilter((prev) => ({
125+
...prev,
126+
selectedProf: [prof.id, DEFAULTSUBPROFID.ALL],
127+
}))
128+
}
129+
/>
130+
))}
131+
</UlWithArrow>
132+
</div>
133+
)
134+
}
135+
136+
interface ProfIconProp extends ImgHTMLAttributes<HTMLImageElement> {
137+
name: string
138+
profId: string
139+
selected: boolean
140+
onProfClick: () => void
141+
}
142+
143+
const ProfIcon: FC<ProfIconProp> = ({
144+
name,
145+
profId,
146+
selected,
147+
onProfClick,
148+
...restImgProps
149+
}) => {
150+
return (
151+
<li
152+
className="grow cursor-pointer relative flex justify-center items-center p-2 min-w-[48px]"
153+
title={name}
154+
role="presentation"
155+
onClick={onProfClick}
156+
>
157+
{selected && (
158+
<div className="w-full h-1 bg-black dark:bg-white absolute bottom-full left-0 rounded" />
159+
)}
160+
{(Object.values(DEFAULTPROFID) as string[]).includes(profId) ? (
161+
<H5 className="!text-xs sm:!text-base truncate m-0">{name}</H5>
162+
) : (
163+
<img
164+
{...restImgProps}
165+
className="invert dark:invert-0"
166+
src={'/assets/prof-icons/' + profId + '.png'}
167+
alt=""
168+
title={name}
169+
/>
170+
)}
171+
</li>
172+
)
173+
}
174+
175+
interface UlWithArrowProp extends HTMLAttributes<HTMLUListElement> {}
176+
177+
const UlWithArrow: FC<UlWithArrowProp> = ({ className, ...ulProps }) => {
178+
const containerRef = useRef<HTMLUListElement>(null)
179+
const [showLeft, setShowLeft] = useState(false)
180+
const [showRight, setShowRight] = useState(false)
181+
182+
const isOverflow = useMemo(() => showLeft || showRight, [showLeft, showRight])
183+
184+
useEffect(() => {
185+
const checkScroll = () => {
186+
const el = containerRef.current
187+
if (!el) return
188+
const { scrollLeft, scrollWidth, clientWidth } = el
189+
190+
setShowLeft(scrollLeft > 0)
191+
setShowRight(scrollLeft + clientWidth < scrollWidth - 1)
192+
}
193+
194+
const el = containerRef.current
195+
if (!el) return
196+
197+
checkScroll()
198+
el.addEventListener('scroll', checkScroll)
199+
200+
const resizeObserver = new ResizeObserver(checkScroll)
201+
resizeObserver.observe(el)
202+
resizeObserver.observe(el.firstElementChild as Element)
203+
204+
return () => {
205+
el.removeEventListener('scroll', checkScroll)
206+
resizeObserver.disconnect()
207+
}
208+
}, [])
209+
210+
return (
211+
<div className="flex items-center relative w-full">
212+
{showLeft && (
213+
<Icon
214+
icon="chevron-left"
215+
className="absolute left-0 top-1/2 -translate-y-1/2 invert z-10"
216+
/>
217+
)}
218+
<ul
219+
{...ulProps}
220+
ref={containerRef}
221+
className={clsx(
222+
'flex overflow-auto items-center w-full',
223+
!isOverflow && 'justify-center',
224+
className,
225+
)}
226+
/>
227+
{showRight && (
228+
<Icon
229+
icon="chevron-right"
230+
className="absolute right-0 top-1/2 -translate-y-1/2 invert z-10"
231+
/>
232+
)}
233+
</div>
234+
)
235+
}
Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
import { FC, useCallback, useRef } from 'react'
1+
import { Button } from '@blueprintjs/core'
2+
import { Popover2 } from '@blueprintjs/popover2'
3+
4+
import { FC, useCallback, useEffect, useRef } from 'react'
5+
6+
import { OperatorBackToTop } from 'components/editor/operator/sheet/sheetOperator/toolBox/OperatorBackToTop'
7+
import { OperatorMutipleSelect } from 'components/editor/operator/sheet/sheetOperator/toolBox/OperatorMutipleSelect'
8+
import { OperatorRaritySelect } from 'components/editor/operator/sheet/sheetOperator/toolBox/OperatorRaritySelect'
29

310
import { OperatorNoData } from '../../../editor/operator/sheet/SheetNoneData'
4-
import { ProfClassificationWithFilters } from '../../../editor/operator/sheet/sheetOperator/ProfClassificationWithFilters'
5-
import { useOperatorFilterProvider } from '../../../editor/operator/sheet/sheetOperator/SheetOperatorFilterProvider'
11+
import {
12+
defaultPagination,
13+
useOperatorFilterProvider,
14+
} from '../../../editor/operator/sheet/sheetOperator/SheetOperatorFilterProvider'
615
import { SheetOperatorItem } from '../../../editor/operator/sheet/sheetOperator/SheetOperatorItem'
716
import { ShowMore } from '../../../editor/operator/sheet/sheetOperator/ShowMore'
17+
import { ProfClassification } from './ProfClassification'
818

919
interface SheetListProps {}
1020

@@ -23,31 +33,56 @@ export const SheetList: FC<SheetListProps> = () => {
2333

2434
const {
2535
operatorFiltered: { data: operatorFilteredData },
36+
useProfFilterState: [{ selectedProf }],
37+
usePaginationFilterState: [_, setPaginationFilter],
2638
} = useOperatorFilterProvider()
2739

40+
useEffect(() => {
41+
toTop()
42+
setPaginationFilter(defaultPagination)
43+
}, [selectedProf, setPaginationFilter, toTop])
44+
2845
return (
29-
<div className="flex h-full">
30-
<div className="grow px-1 py-4 overflow-auto">
31-
{operatorFilteredData.length ? (
32-
<>
33-
<div
34-
key="operatorContainer"
35-
className="flex flex-wrap items-start content-start overscroll-contain relative"
36-
ref={operatorScrollRef}
37-
>
38-
{operatorFilteredData.map(({ name }, index) => (
39-
<div className="flex items-center flex-0 w-32 h-32" key={index}>
40-
<SheetOperatorItem {...{ name }} />
41-
</div>
42-
))}
43-
</div>
44-
<ShowMore {...{ toTop }} />
45-
</>
46-
) : (
47-
<OperatorNoData />
48-
)}
46+
<div className="flex flex-col h-full">
47+
<div className="flex h-full w-full overflow-auto">
48+
<div className="grow px-1 py-4">
49+
{operatorFilteredData.length ? (
50+
<>
51+
<div
52+
key="operatorContainer"
53+
className="grid auto-rows-auto grid-cols-[repeat(auto-fit,minmax(128px,1fr))]"
54+
ref={operatorScrollRef}
55+
>
56+
{operatorFilteredData.map(({ name }, index) => (
57+
<div
58+
className="flex items-center flex-0 w-full h-32"
59+
key={index}
60+
>
61+
<SheetOperatorItem {...{ name }} />
62+
</div>
63+
))}
64+
</div>
65+
<ShowMore {...{ toTop }} />
66+
</>
67+
) : (
68+
<OperatorNoData />
69+
)}
70+
</div>
71+
<div className="h-full sticky top-0 self-start shrink-0 z-10 flex flex-col items-center justify-center">
72+
<Popover2
73+
content={
74+
<>
75+
<OperatorRaritySelect />
76+
</>
77+
}
78+
>
79+
<Button minimal icon="filter-list" />
80+
</Popover2>
81+
<OperatorMutipleSelect />
82+
<OperatorBackToTop {...{ toTop }} />
83+
</div>
4984
</div>
50-
<ProfClassificationWithFilters {...{ toTop }} />
85+
<ProfClassification />
5186
</div>
5287
)
5388
}

0 commit comments

Comments
 (0)