10 Commits

Author SHA1 Message Date
zihluwang b000336d22 Merge pull request #9 from zihluwang/develop
Enhance firearms management with filtering, display, and UI improvements
2026-04-09 17:27:22 +08:00
zihluwang cf2b57f745 feat: reinstall packages 2026-04-09 17:25:31 +08:00
zihluwang a1984c3ecb Merge remote-tracking branch 'origin/main' into develop
# Conflicts:
#	package.json
#	pnpm-lock.yaml
2026-04-09 17:24:21 +08:00
zihluwang 3af4650d32 Merge pull request #8 from zihluwang/dependabot/npm_and_yarn/dependency-updates-1cafa9d752 2026-04-09 17:19:39 +08:00
dependabot[bot] a36c539ef1 chore: bump the dependency-updates group with 6 updates
Bumps the dependency-updates group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.4` | `19.2.5` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.4` | `19.2.5` |
| [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) | `7.13.2` | `7.14.0` |
| [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) | `7.13.2` | `7.14.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.19.15` | `22.19.17` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.0.3` | `8.0.8` |


Updates `react` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react)

Updates `react-dom` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react-dom)

Updates `react-router` from 7.13.2 to 7.14.0
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.14.0/packages/react-router)

Updates `react-router-dom` from 7.13.2 to 7.14.0
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.14.0/packages/react-router-dom)

Updates `@types/node` from 22.19.15 to 22.19.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `vite` from 8.0.3 to 8.0.8
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.8/packages/vite)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dependency-updates
- dependency-name: react-dom
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dependency-updates
- dependency-name: react-router
  dependency-version: 7.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dependency-updates
- dependency-name: react-router-dom
  dependency-version: 7.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dependency-updates
- dependency-name: "@types/node"
  dependency-version: 22.19.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dependency-updates
- dependency-name: vite
  dependency-version: 8.0.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dependency-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-09 07:57:55 +00:00
zihluwang dad5c191fa feat: add tarball build script to package.json 2026-04-09 14:33:18 +08:00
zihluwang 78fa02e618 feat: add bullet calibre display to FirearmsPage 2026-04-09 14:30:21 +08:00
zihluwang 63f9885aa2 feat: add additional firearm attributes and DPS calculation to FirearmsPage 2026-04-09 14:17:38 +08:00
zihluwang 7f50fafee8 feat: add tag API and integrate tag selection in modifications page 2026-04-07 11:59:37 +08:00
zihluwang 3da706402d feat: enhance modification display with copy functionality and improved styling 2026-04-07 11:17:14 +08:00
8 changed files with 538 additions and 451 deletions
+7 -6
View File
@@ -6,6 +6,7 @@
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"build:tar": "pnpm build && tar -czf dist.tar.gz dist",
"lint": "eslint .",
"preview": "vite preview",
"deploy": "pnpm build && gh-pages -d dist",
@@ -19,23 +20,23 @@
"antd": "^6.3.5",
"axios": "^1.14.0",
"dayjs": "^1.11.20",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react": "^19.2.5",
"react-dom": "^19.2.5",
"react-redux": "^9.2.0",
"react-router": "^7.13.2",
"react-router-dom": "^7.13.2",
"react-router": "^7.14.0",
"react-router-dom": "^7.14.0",
"redux-persist": "^6.0.0",
"tailwindcss": "^4.2.2"
},
"devDependencies": {
"@types/node": "^22.19.15",
"@types/node": "^22.19.17",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
"globals": "^17.4.0",
"prettier": "^3.8.1",
"typescript": "~6.0.2",
"vite": "^8.0.3"
"vite": "^8.0.8"
},
"pnpm": {
"ignoredBuiltDependencies": [
+422 -429
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,2 +1,3 @@
export * as FirearmApi from "./firearm-api"
export * as ModificationApi from "./modification-api"
export * as TagApi from "./tag-api"
+8
View File
@@ -4,17 +4,25 @@ import { asUrlSearchParam } from "@/utils/query-param-utils.ts"
interface ModificationParams extends PageQueryParams {
firearmId?: string
tags?: string[]
}
export async function getModifications(params?: ModificationParams): Promise<Page<Modification>> {
let uri = "/modifications"
const urlSearchParams = asUrlSearchParam(params)
if (params?.firearmId) {
urlSearchParams.append("firearmId", "" + params.firearmId)
}
if (params?.tags) {
params.tags.forEach((tag) => urlSearchParams.append("tags", tag))
}
if (urlSearchParams.size > 0) {
uri = uri.concat("?", urlSearchParams.toString())
}
const { data } = await WebClient.get<Page<Modification>>(uri)
return data
}
+18
View File
@@ -0,0 +1,18 @@
import { WebClient } from "@/shared/web-client"
export async function getTags(firearmId?: number): Promise<string[]> {
let uri = "/tags"
const urlSearchParam = new URLSearchParams()
if (firearmId) {
urlSearchParam.append("firearmId", "" + firearmId)
}
if (urlSearchParam.size > 0) {
uri = uri.concat("?", urlSearchParam.toString())
}
const { data } = await WebClient.get<string[]>(uri)
return data
}
+16
View File
@@ -18,6 +18,10 @@ const firearmTypeText: Record<FirearmType, string> = {
const allTypeValue = "ALL"
type FirearmTypeFilter = FirearmType | typeof allTypeValue
function asDps(fireRate: number, damage: number) {
return ((fireRate / 60) * damage).toFixed(2)
}
export default function FirearmsPage() {
const [page, setPage] = useState<number>(1)
const [typeFilter, setTypeFilter] = useState<FirearmTypeFilter>(allTypeValue)
@@ -79,6 +83,18 @@ export default function FirearmsPage() {
<strong></strong>
{firearm.level}
</Typography.Text>
<Typography.Text>
<strong></strong>
{firearm.calibre}
</Typography.Text>
<Typography.Text>
<strong></strong>
{asDps(firearm.fireRate, firearm.armourDamage)}
</Typography.Text>
<Typography.Text>
<strong></strong>
{asDps(firearm.fireRate, firearm.bodyDamage)}
</Typography.Text>
<Typography.Paragraph
style={{ marginBottom: 0 }}
type="secondary"
+62 -16
View File
@@ -1,7 +1,7 @@
import { useEffect, useMemo, useState } from "react"
import { Link, useSearchParams } from "react-router-dom"
import { Button, Card, Col, Pagination, Row, Space, Tag, Typography } from "antd"
import { ModificationApi } from "@/api"
import { Button, Card, Col, Pagination, Row, Select, Space, Tag, Typography } from "antd"
import { ModificationApi, TagApi } from "@/api"
import { Modification } from "@/types"
const pageSize = 12
@@ -12,8 +12,17 @@ export default function ModCodesPage() {
const [page, setPage] = useState<number>(1)
const [modifications, setModifications] = useState<Modification[]>([])
const [tagOptions, setTagOptions] = useState<string[]>([])
const [selectedTags, setSelectedTags] = useState<string[]>([])
const [total, setTotal] = useState<number>(0)
useEffect(() => {
const _firearmId = firearmId ? +firearmId : (void 0)
TagApi.getTags(_firearmId).then((tags) => {
setTagOptions(tags)
})
}, [])
useEffect(() => {
ModificationApi.getModifications({
page: page - 1,
@@ -21,30 +30,55 @@ export default function ModCodesPage() {
sortBy: "id",
direction: "ASC",
firearmId,
tags: selectedTags,
}).then((pagedData) => {
setModifications(pagedData.items)
setTotal(pagedData.totalElements)
})
}, [page, firearmId])
}, [page, firearmId, selectedTags])
useEffect(() => {
setPage(1)
}, [firearmId])
useEffect(() => {
setPage(1)
}, [selectedTags])
return (
<>
<div className="mb-4 flex items-center justify-between gap-4">
<Typography.Title level={4} className="mb-0!">
</Typography.Title>
{firearmId && (
<Space>
<Tag color="geekblue"> ID: {firearmId}</Tag>
<Space wrap>
<span></span>
<Select<string[]>
mode="multiple"
allowClear
placeholder="请选择标签"
className="w-64"
value={selectedTags}
options={tagOptions.map((tag) => ({ value: tag, label: tag }))}
onChange={(values) => {
setSelectedTags(values)
}}
/>
{firearmId && <Tag color="geekblue"> ID: {firearmId}</Tag>}
{(firearmId || selectedTags.length > 0) && (
<Link to="/mod-codes">
<Button type="link"></Button>
<Button
type="link"
onClick={() => {
setSelectedTags([])
setPage(1)
}}
>
</Button>
</Link>
</Space>
)}
)}
</Space>
</div>
<div className="mb-6">
@@ -56,13 +90,22 @@ export default function ModCodesPage() {
variant="outlined"
styles={{
header: { minHeight: 56 },
}}
>
}}>
<div className="flex flex-col gap-3">
<Typography.Paragraph className="mb-0!" copyable={{ text: modification.code }}>
<strong></strong>
{modification.code}
</Typography.Paragraph>
<div className="flex items-center justify-between gap-2">
<span>
<strong></strong>
<code className="bg-gray-400 px-2 py-1 rounded text-sm text-white">
{modification.code}
</code>
</span>
<Button
type="text"
size="small"
onClick={() => navigator.clipboard.writeText(modification.code)}>
</Button>
</div>
<Typography.Text>
<strong></strong>
@@ -77,7 +120,10 @@ export default function ModCodesPage() {
</div>
)}
<Typography.Paragraph style={{ marginBottom: 0 }} type="secondary" ellipsis={{ rows: 3 }}>
<Typography.Paragraph
style={{ marginBottom: 0 }}
type="secondary"
ellipsis={{ rows: 3 }}>
{modification.note || "暂无备注"}
</Typography.Paragraph>
+4
View File
@@ -23,6 +23,10 @@ export interface Firearm {
name: string
type: FirearmType
level: string
calibre: string
fireRate: number
armourDamage: number
bodyDamage: number
review: string
}