Commit e200d3c7 authored by timel's avatar timel Committed by Chunchi Che

feat: waiting msg, card dropdown menu

parent 2a1217db
...@@ -53,6 +53,8 @@ import onMsgUpdateHp from "./updateHp"; ...@@ -53,6 +53,8 @@ import onMsgUpdateHp from "./updateHp";
import onMsgWait from "./wait"; import onMsgWait from "./wait";
import onMsgWin from "./win"; import onMsgWin from "./win";
import { showWaiting } from "@/ui/Duel/Message";
const ActiveList = [ const ActiveList = [
"select_idle_cmd", "select_idle_cmd",
"select_place", "select_place",
...@@ -77,7 +79,7 @@ async function _handleGameMsg(pb: ygopro.YgoStocMsg) { ...@@ -77,7 +79,7 @@ async function _handleGameMsg(pb: ygopro.YgoStocMsg) {
const msg = pb.stoc_game_msg; const msg = pb.stoc_game_msg;
if (ActiveList.includes(msg.gameMsg)) { if (ActiveList.includes(msg.gameMsg)) {
matStore.waiting = false; showWaiting(false);
} }
switch (msg.gameMsg) { switch (msg.gameMsg) {
......
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { cardStore, matStore } from "@/stores"; import { cardStore, matStore } from "@/stores";
import { showWaiting } from "@/ui/Duel/Message";
export default (_wait: ygopro.StocGameMessage.MsgWait) => { export default (_wait: ygopro.StocGameMessage.MsgWait) => {
for (const card of cardStore.inner) { for (const card of cardStore.inner) {
card.idleInteractivities = []; card.idleInteractivities = [];
} }
matStore.waiting = true; showWaiting(true);
}; };
...@@ -33,8 +33,6 @@ export interface MatState { ...@@ -33,8 +33,6 @@ export interface MatState {
reason: string; reason: string;
}; };
waiting: boolean;
unimplemented: number; // 未处理的`Message` unimplemented: number; // 未处理的`Message`
tossResult?: string; // 骰子/硬币结果 tossResult?: string; // 骰子/硬币结果
......
.card-modal-desc { .card-modal-desc {
line-height: 1.6; line-height: 1.6;
font-size: 15px; font-size: 14px;
font-family: var(--theme-font); font-family: var(--theme-font);
max-height: calc(100% - 237px); max-height: calc(100% - 237px);
overflow-y: overlay; overflow-y: overlay;
......
...@@ -79,6 +79,7 @@ export const CardModal = () => { ...@@ -79,6 +79,7 @@ export const CardModal = () => {
mask={false} mask={false}
title={name} title={name}
closeIcon={<LeftOutlined />} closeIcon={<LeftOutlined />}
width={350}
> >
<div className="card-modal-container"> <div className="card-modal-container">
<Space <Space
......
import { notification } from "antd"; import { notification, message } from "antd";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useSnapshot } from "valtio"; import { useSnapshot } from "valtio";
...@@ -14,21 +14,27 @@ const style = { ...@@ -14,21 +14,27 @@ const style = {
}; };
const NeosConfig = useConfig(); const NeosConfig = useConfig();
let globalMsgApi: ReturnType<typeof message.useMessage>[0] | undefined;
export const HintNotification = () => { export const HintNotification = () => {
const snap = useSnapshot(matStore); const snap = useSnapshot(matStore);
const hintState = snap.hint; const hintState = snap.hint;
const toss = snap.tossResult; const toss = snap.tossResult;
const currentPhase = snap.phase.currentPhase; const currentPhase = snap.phase.currentPhase;
const waiting = snap.waiting; // const waiting = snap.waiting;
const result = snap.result; const result = snap.result;
const [api, contextHolder] = notification.useNotification({ const [notify, notifyContextHolder] = notification.useNotification({
maxCount: NeosConfig.ui.hint.maxCount,
});
const [msgApi, msgContextHolder] = message.useMessage({
maxCount: NeosConfig.ui.hint.maxCount, maxCount: NeosConfig.ui.hint.maxCount,
}); });
globalMsgApi = msgApi;
useEffect(() => { useEffect(() => {
if (hintState && hintState.msg) { if (hintState && hintState.msg) {
api.open({ notify.open({
message: `${hintState.msg}`, message: `${hintState.msg}`,
placement: "topLeft", placement: "topLeft",
style: style, style: style,
...@@ -38,7 +44,7 @@ export const HintNotification = () => { ...@@ -38,7 +44,7 @@ export const HintNotification = () => {
useEffect(() => { useEffect(() => {
if (toss) { if (toss) {
api.open({ notify.open({
message: `${toss}`, message: `${toss}`,
placement: "topLeft", placement: "topLeft",
style: style, style: style,
...@@ -52,7 +58,7 @@ export const HintNotification = () => { ...@@ -52,7 +58,7 @@ export const HintNotification = () => {
"!system", "!system",
Phase2StringCodeMap.get(currentPhase) ?? 0 Phase2StringCodeMap.get(currentPhase) ?? 0
); );
api.open({ notify.open({
message, message,
placement: "topRight", placement: "topRight",
style: style, style: style,
...@@ -63,21 +69,10 @@ export const HintNotification = () => { ...@@ -63,21 +69,10 @@ export const HintNotification = () => {
} }
}, [currentPhase]); }, [currentPhase]);
useEffect(() => {
if (waiting) {
api.open({
message: fetchStrings("!system", 1390),
placement: "top",
duration: NeosConfig.ui.hint.waitingDuration,
style: style,
});
}
}, [waiting]);
useEffect(() => { useEffect(() => {
if (result) { if (result) {
const message = result.isWin ? "Win" : "Defeated" + " " + result.reason; const message = result.isWin ? "Win" : "Defeated" + " " + result.reason;
api.open({ notify.open({
message, message,
placement: "bottom", placement: "bottom",
style: style, style: style,
...@@ -85,5 +80,36 @@ export const HintNotification = () => { ...@@ -85,5 +80,36 @@ export const HintNotification = () => {
} }
}, [result]); }, [result]);
return <>{contextHolder}</>; return (
<>
{notifyContextHolder}
{msgContextHolder}
</>
);
};
// 防抖的waiting msg
let isWaiting = false;
let destoryTimer: NodeJS.Timeout | undefined;
const waitingKey = "waiting";
export const showWaiting = (open: boolean) => {
if (open) {
if (!isWaiting) {
globalMsgApi?.open({
type: "loading",
content: fetchStrings("!system", 1390),
key: waitingKey,
});
clearTimeout(destoryTimer);
isWaiting = true;
destoryTimer = undefined;
}
} else {
if (!destoryTimer) {
destoryTimer = setTimeout(() => {
globalMsgApi?.destroy(waitingKey);
isWaiting = false;
}, 1000);
}
}
}; };
...@@ -18,7 +18,6 @@ section#mat { ...@@ -18,7 +18,6 @@ section#mat {
transition: 0.2s scale; transition: 0.2s scale;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
scale: 1.05;
} }
.card-cover, .card-cover,
.card-back { .card-back {
...@@ -113,3 +112,9 @@ section#mat { ...@@ -113,3 +112,9 @@ section#mat {
filter: brightness(1) contrast(1); filter: brightness(1) contrast(1);
} }
} }
.card-dropdown {
.ant-dropdown-menu {
background-color: #333;
}
}
...@@ -23,6 +23,14 @@ import type { SpringApiProps } from "./springs/types"; ...@@ -23,6 +23,14 @@ import type { SpringApiProps } from "./springs/types";
import { YgoCard } from "@/ui/Shared"; import { YgoCard } from "@/ui/Shared";
import { showCardModal } from "@/ui/Duel/Message/CardModal"; import { showCardModal } from "@/ui/Duel/Message/CardModal";
import { Button, Dropdown } from "antd";
import {
UploadOutlined,
DownloadOutlined,
UpOutlined,
} from "@ant-design/icons";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, SZONE, TZONE } = const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, SZONE, TZONE } =
...@@ -130,7 +138,20 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => { ...@@ -130,7 +138,20 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
useEffect(() => { useEffect(() => {
setHighlight(!!idleInteractivities.length); setHighlight(!!idleInteractivities.length);
}, [idleInteractivities]); }, [idleInteractivities]);
const items = [
{
key: "1",
label: "正面攻表召唤",
},
{
key: "2",
label: "反面守表召唤",
},
{
key: "3",
label: "效果发动",
},
];
return ( return (
<animated.div <animated.div
className="mat-card" className="mat-card"
...@@ -160,6 +181,13 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => { ...@@ -160,6 +181,13 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
> >
<div className="card-focus" /> <div className="card-focus" />
<div className="card-shadow" /> <div className="card-shadow" />
<Dropdown
menu={{ items }}
placement="bottom"
overlayClassName="card-dropdown"
arrow={{ pointAtCenter: true }}
trigger={["click"]}
>
<div className={classnames("card-img-wrap", { focus: classFocus })}> <div className={classnames("card-img-wrap", { focus: classFocus })}>
<YgoCard <YgoCard
className={classnames("card-cover")} className={classnames("card-cover")}
...@@ -167,6 +195,7 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => { ...@@ -167,6 +195,7 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
/> />
<YgoCard className="card-back" isBack /> <YgoCard className="card-back" isBack />
</div> </div>
</Dropdown>
{snap.selected ? <div className="card-streamer" /> : <></>} {snap.selected ? <div className="card-streamer" /> : <></>}
</animated.div> </animated.div>
); );
......
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