Commit 07eb4ed6 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/mouseEvent' into 'main'

feat: add mouse event on deck

See merge request mycard/Neos!296
parents 5ebda8bb c1c288c5
Pipeline #23380 passed with stages
in 13 minutes and 49 seconds
......@@ -13,6 +13,7 @@ import {
Dropdown,
Input,
type MenuProps,
message,
Pagination,
Space,
} from "antd";
......@@ -26,12 +27,13 @@ import { proxy, useSnapshot } from "valtio";
import { subscribeKey } from "valtio/utils";
import { type CardMeta, searchCards } from "@/api";
import { isToken } from "@/common";
import { isExtraDeckCard, isToken } from "@/common";
import { FtsConditions } from "@/middleware/sqlite/fts";
import { deckStore, type IDeck, initStore } from "@/stores";
import {
Background,
DeckCard,
DeckCardMouseUpEvent,
DeckZone,
IconFont,
Loading,
......@@ -159,6 +161,53 @@ export const DeckEditor: React.FC<{
useEffect(() => {
iDeckToEditingDeck(deck).then(editDeckStore.set);
}, [deck]);
const handleSwitchCard = (type: Type, card: CardMeta) => {
const cardType = card.data.type ?? 0;
const isSide = type === "side";
const targetType = isSide
? isExtraDeckCard(cardType)
? "extra"
: "main"
: "side";
const { result, reason } = editDeckStore.canAdd(card, targetType, type);
if (result) {
editDeckStore.remove(type, card);
editDeckStore.add(targetType, card);
} else {
message.error(reason);
}
};
const showSelectedCard = (card: CardMeta) => {
selectedCard.id = card.id;
selectedCard.open = true;
};
const handleMouseUp = (
type: "main" | "extra" | "side",
payload: DeckCardMouseUpEvent,
) => {
const { event, card } = payload;
switch (event.button) {
// 左键
case 0:
showSelectedCard(card);
break;
// 中键
case 1:
handleSwitchCard(type, card);
break;
// 右键
case 2:
editDeckStore.remove(type, card);
break;
default:
break;
}
event.preventDefault();
};
return (
<div className={styles.container}>
<Space className={styles.title}>
......@@ -215,11 +264,7 @@ export const DeckEditor: React.FC<{
editDeckStore.remove(source, card);
}
}}
onElementClick={(card) => {
selectedCard.id = card.id;
selectedCard.open = true;
}}
onElementRightClick={(card) => editDeckStore.remove(type, card)}
onElementMouseUp={(event) => handleMouseUp(type, event)}
/>
))}
</ScrollableArea>
......@@ -423,6 +468,53 @@ const SearchResults: React.FC<{
const endIndex = startIndex + itemsPerPage;
const currentData = results.slice(startIndex, endIndex);
const showSelectedCard = (card: CardMeta) => {
selectedCard.id = card.id;
selectedCard.open = true;
};
const handleAddCardToMain = (card: CardMeta) => {
const cardType = card.data.type ?? 0;
const isExtraCard = isExtraDeckCard(cardType);
const type = isExtraCard ? "extra" : "main";
const { result, reason } = editDeckStore.canAdd(card, type, "search");
if (result) {
editDeckStore.add(type, card);
} else {
message.error(reason);
}
};
const handleAddCardToSide = (card: CardMeta) => {
const { result, reason } = editDeckStore.canAdd(card, "side", "search");
if (result) {
editDeckStore.add("side", card);
} else {
message.error(reason);
}
};
/** safari 不支持 onAuxClick,所以使用 mousedown 模拟 */
const handleMouseUp = (payload: DeckCardMouseUpEvent) => {
const { event, card } = payload;
switch (event.button) {
// 左键
case 0:
showSelectedCard(card);
break;
// 中键
case 1:
handleAddCardToSide(card);
break;
// 右键
case 2:
handleAddCardToMain(card);
break;
default:
break;
}
};
return (
<>
<div className={styles["search-cards"]}>
......@@ -431,10 +523,8 @@ const SearchResults: React.FC<{
value={card}
key={card.id}
source="search"
onClick={() => {
selectedCard.id = card.id;
selectedCard.open = true;
}}
onMouseUp={handleMouseUp}
onMouseEnter={() => showSelectedCard(card)}
/>
))}
</div>
......
......@@ -10,13 +10,18 @@ import styles from "./index.module.scss";
const { assetsPath } = useConfig();
export interface DeckCardMouseUpEvent {
event: React.MouseEvent;
card: CardMeta;
}
/** 组卡页和Side页使用的单张卡片,增加了文字和禁限数量 */
export const DeckCard: React.FC<{
value: CardMeta;
source: Type | "search";
onRightClick?: () => void;
onClick?: () => void;
}> = memo(({ value, source, onRightClick, onClick }) => {
onMouseUp?: (event: DeckCardMouseUpEvent) => void;
onMouseEnter?: () => void;
}> = memo(({ value, source, onMouseUp, onMouseEnter }) => {
const ref = useRef<HTMLDivElement>(null);
const [{ isDragging }, drag] = useDrag({
type: "Card",
......@@ -33,10 +38,15 @@ export const DeckCard: React.FC<{
className={styles.card}
ref={ref}
style={{ opacity: isDragging && source !== "search" ? 0 : 1 }}
onClick={onClick}
onMouseUp={(event) =>
onMouseUp?.({
event,
card: value,
})
}
onMouseEnter={onMouseEnter}
onContextMenu={(e) => {
e.preventDefault();
onRightClick?.();
}}
>
{showText && <div className={styles.cardname}>{value.text.name}</div>}
......
......@@ -5,7 +5,7 @@ import { useDrop } from "react-dnd";
import { CardMeta } from "@/api";
import { DeckCard } from "../DeckCard";
import { DeckCard, DeckCardMouseUpEvent } from "../DeckCard";
import styles from "./index.module.scss";
/** 正在组卡的zone,包括main/extra/side
......@@ -24,15 +24,13 @@ export const DeckZone: React.FC<{
source: Type | "search",
destination: Type,
) => void;
onElementClick: (card: CardMeta) => void;
onElementRightClick?: (card: CardMeta) => void;
onElementMouseUp: (event: DeckCardMouseUpEvent) => void;
}> = ({
type,
cards,
canAdd,
onChange,
onElementClick,
onElementRightClick,
onElementMouseUp: onElementMouseUp,
}) => {
const { message } = App.useApp();
const [allowToDrop, setAllowToDrop] = useState(false);
......@@ -72,12 +70,7 @@ export const DeckZone: React.FC<{
value={card}
key={card.id + i + type}
source={type}
onClick={() => {
onElementClick(card);
}}
onRightClick={() => {
onElementRightClick?.(card);
}}
onMouseUp={onElementMouseUp}
/>
))}
<div className={styles["editing-zone-name"]}>
......
......@@ -115,7 +115,7 @@ export const Component: React.FC = () => {
cards={[...deck[type]].map((id) => fetchCard(id))}
canAdd={canAdd}
onChange={onChange}
onElementClick={(card) => setSelectedCard(card.id)}
onElementMouseUp={(event) => setSelectedCard(event.card.id)}
/>
))}
</ScrollableArea>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment