Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion public/yxp_images
12 changes: 12 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
cursor: pointer;
}

.card img {
width: 100%;
aspect-ratio: 425 / 685;
object-fit: contain;
}

.cardname,
.cardlevel {
margin-inline-end: 0 !important;
Expand Down Expand Up @@ -64,3 +70,9 @@
.ant-input-number {
width: 60px;
}

.ant-tree-select-dropdown .ant-select-tree-node-content-wrapper,
.ant-tree-select-dropdown .ant-select-tree-node-content-wrapper * {
color: rgba(255, 255, 255, 0.85) !important;
-webkit-text-fill-color: rgba(255, 255, 255, 0.85) !important;
}
17 changes: 16 additions & 1 deletion src/Simulator.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,23 @@ function buildTree(items, l) {
const tree = [];

for (const item of items) {
const sid = String(item.id);

// Dream cards: D-prefix → add under "Dream" category
if (sid.startsWith('D')) {
let dreamNode = tree.find(n => n.idPart === 'dream');
if (!dreamNode) {
dreamNode = { idPart: 'dream', value: 'dream', title: l('Fate Branches'), disabled: true, children: [] };
tree.push(dreamNode);
}
dreamNode.children.push({ value: item.id, title: l(item.name) });
continue;
}

const ID_RE = /^(\d)(\d)(\d)(\d{2})(\d)$/;

// 1. Extract levels
const s = String(item.id).padStart(6, "0");
const s = sid.padStart(6, "0");
const m = s.match(ID_RE);
if (!m) continue;
const [, lv1, lv2, lv3] = m;
Expand Down Expand Up @@ -432,6 +445,7 @@ const Simulator = ({ l, form, setResult, setIsModalOpen, messageApi }) => {
<Form.Item label={l("Character")} name={[roleField, "character"]}>
<Select
showSearch
optionFilterProp="label"
popupMatchSelectWidth={false}
options={Object.keys(CHARACTER_ID_TO_NAME).map((key) => ({
value: key,
Expand All @@ -448,6 +462,7 @@ const Simulator = ({ l, form, setResult, setIsModalOpen, messageApi }) => {
<Form.Item label={l("Side job")} name={[roleField, "side_job"]}>
<Select
showSearch
optionFilterProp="label"
popupMatchSelectWidth={false}
options={Object.keys(sideJob).map((key) => ({
value: key,
Expand Down
63 changes: 33 additions & 30 deletions src/components/SortableCard.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// src/components/SortableCard.jsx
import React from "react";
import {
UserOutlined,
QuestionOutlined,
PlayCircleOutlined,
ClearOutlined,
} from "@ant-design/icons";
import { useSortable } from "@dnd-kit/sortable";
Expand Down Expand Up @@ -34,8 +31,6 @@ export default function SortableCard({
// 将 transform 对象转换为行内样式字符串
const style = {
transform: CSS.Transform.toString(transform),
// transition,
// 当正在拖拽时可以微调样式,比如将透明度降低
opacity: isDragging ? 0.5 : 1,
height: "100%",
display: "flex",
Expand All @@ -46,9 +41,10 @@ export default function SortableCard({
// 从 Form 中获取当前的 cards 数组,找到第 index 个卡片
const cards = Form.useWatch([roleField, "cards"]) || [];
const card = cards[index] || {};
const isDream = String(card.card_id).startsWith('D');
const src = card.card_id
? `yxp_images/${l.lang === "en" ? "en" : "zh"}/${card.card_id + card.level - 1}.png`
: `yxp_images/${l.lang === "en" ? "en" : "zh"}/Deviation Syndrome1.png`;
? `yxp_images/${l.lang === "en" ? "en" : "zh"}/${String(card.card_id).slice(0, -1) + card.level}.png`
: null;

return (
<div ref={setNodeRef} style={style}>
Expand All @@ -72,6 +68,22 @@ export default function SortableCard({
)}
</Form.Item>

<div className="cardlevel" style={{ textAlign: 'center' }}>
<Rate
tabIndex='-1'
count={isDream ? 5 : 3}
allowClear={false}
value={card.level}
onChange={(newLevel) => {
if (!card.card_id) return;
const base = String(card.card_id).slice(0, -1);
const entry = swogi[base + newLevel];
if (!entry || entry.does_not_exist) return;
form.setFieldValue([roleField, "cards", field.name, "level"], newLevel);
}}
/>
</div>

<Form.Item name={[field.name, "card_id"]} className='cardname'>
<TreeSelect
placeholder='Select'
Expand All @@ -92,33 +104,24 @@ export default function SortableCard({
popupMatchSelectWidth={false}
treeData={treeData}
style={{ width: "100%" }}
onChange={(e) => {
const level = form.getFieldValue([
roleField,
"cards",
field.name,
"level",
]);
if (swogi[String(e - 1 + level)].does_not_exist) {
form.setFieldValue([roleField, "cards", field.name], {
card_id: e,
level: swogi[String(e)].does_not_exist
? swogi[String(e + 1)].does_not_exist
? swogi[String(e + 2)].does_not_exist
? 0
: 3
: 2
: 1,
});
onChange={(newCardId) => {
let lvl = card.level || 1;
const newIsDream = String(newCardId).startsWith('D');
const oldIsDream = String(card.card_id).startsWith('D');
if (newIsDream && !oldIsDream) {
lvl = 5;
} else {
const base = String(newCardId).slice(0, -1);
while (lvl > 1 && (!swogi[base + lvl] || swogi[base + lvl].does_not_exist)) lvl--;
while (lvl < 5 && (!swogi[base + lvl] || swogi[base + lvl].does_not_exist)) lvl++;
}
form.setFieldValue([roleField, "cards", field.name], {
card_id: newCardId,
level: lvl,
});
}}
/>
</Form.Item>

{/* 等级评分 */}
<Form.Item name={[field.name, "level"]} className='cardlevel'>
<Rate tabIndex='-1' count={3} allowClear={false} />
</Form.Item>
</div>
);
}