mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-01-14 22:13:48 -08:00
Webatrice: card import wizard (#4397)
This commit is contained in:
4
webclient/src/components/Message/CardCallout.css
Normal file
4
webclient/src/components/Message/CardCallout.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.callout {
|
||||
font-weight: bold;
|
||||
color: green;
|
||||
}
|
||||
87
webclient/src/components/Message/CardCallout.tsx
Normal file
87
webclient/src/components/Message/CardCallout.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
// eslint-disable-next-line
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Popover from '@material-ui/core/Popover';
|
||||
|
||||
import { CardDTO, TokenDTO } from 'services';
|
||||
|
||||
import CardDetails from '../CardDetails/CardDetails';
|
||||
import TokenDetails from '../TokenDetails/TokenDetails';
|
||||
|
||||
import './CardCallout.css';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
popover: {
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
popoverContent: {
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
const CardCallout = ({ name }) => {
|
||||
const classes = useStyles();
|
||||
const [card, setCard] = useState<CardDTO>(null);
|
||||
const [token, setToken] = useState<TokenDTO>(null);
|
||||
const [anchorEl, setAnchorEl] = useState<Element>(null);
|
||||
|
||||
useMemo(async () => {
|
||||
const card = await CardDTO.get(name);
|
||||
if (card) {
|
||||
return setCard(card)
|
||||
}
|
||||
|
||||
const token = await TokenDTO.get(name);
|
||||
if (token) {
|
||||
return setToken(token);
|
||||
}
|
||||
}, [name]);
|
||||
|
||||
const handlePopoverOpen = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handlePopoverClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
return (
|
||||
<span className='callout'>
|
||||
<span
|
||||
onMouseEnter={handlePopoverOpen}
|
||||
onMouseLeave={handlePopoverClose}
|
||||
>{card?.name || token?.name?.value || name}</span>
|
||||
|
||||
{
|
||||
(card || token) && (
|
||||
<Popover
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handlePopoverClose}
|
||||
className={classes.popover}
|
||||
classes={{
|
||||
paper: classes.popoverContent,
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'left',
|
||||
}}
|
||||
>
|
||||
<div className="callout-card">
|
||||
{ card && ( <CardDetails card={card} /> ) }
|
||||
{ token && ( <TokenDetails token={token} /> ) }
|
||||
</div>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardCallout;
|
||||
3
webclient/src/components/Message/Message.css
Normal file
3
webclient/src/components/Message/Message.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.link {
|
||||
color: blue;
|
||||
}
|
||||
105
webclient/src/components/Message/Message.tsx
Normal file
105
webclient/src/components/Message/Message.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
// eslint-disable-next-line
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { NavLink, generatePath } from "react-router-dom";
|
||||
|
||||
import {
|
||||
RouteEnum,
|
||||
URL_REGEX,
|
||||
MESSAGE_SENDER_REGEX,
|
||||
MENTION_REGEX,
|
||||
CARD_CALLOUT_REGEX,
|
||||
CALLOUT_BOUNDARY_REGEX,
|
||||
} from 'types';
|
||||
|
||||
import CardCallout from './CardCallout';
|
||||
import './Message.css';
|
||||
|
||||
const Message = ({ message: { message, messageType, timeOf, timeReceived } }) => (
|
||||
<div className='message'>
|
||||
<div className='message__detail'>
|
||||
<ParsedMessage message={message} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const ParsedMessage = ({ message }) => {
|
||||
const [messageChunks, setMessageChunks] = useState(null);
|
||||
const [name, setName] = useState(null);
|
||||
|
||||
useMemo(() => {
|
||||
const name = message.match(MESSAGE_SENDER_REGEX);
|
||||
|
||||
if (name) {
|
||||
setName(name[1]);
|
||||
}
|
||||
|
||||
setMessageChunks(parseMessage(message));
|
||||
}, [message]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ name && ( <strong><PlayerLink name={name} />:</strong> ) }
|
||||
{ messageChunks }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const PlayerLink = ({ name, label = name }) => (
|
||||
<NavLink className="link" to={generatePath(RouteEnum.PLAYER, { name })}>
|
||||
{label}
|
||||
</NavLink>
|
||||
);
|
||||
|
||||
function parseMessage(message) {
|
||||
return message.replace(MESSAGE_SENDER_REGEX, '')
|
||||
.split(CARD_CALLOUT_REGEX)
|
||||
.filter(chunk => !!chunk)
|
||||
.map(parseChunks);
|
||||
}
|
||||
|
||||
function parseChunks(chunk, index) {
|
||||
if (chunk.match(CARD_CALLOUT_REGEX)) {
|
||||
const name = chunk.replace(CALLOUT_BOUNDARY_REGEX, '').trim();
|
||||
return ( <CardCallout name={name} key={index}></CardCallout> );
|
||||
}
|
||||
|
||||
if (chunk.match(URL_REGEX)) {
|
||||
return parseUrlChunk(chunk);
|
||||
}
|
||||
|
||||
if (chunk.match(MENTION_REGEX)) {
|
||||
return parseMentionChunk(chunk);
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
function parseUrlChunk(chunk) {
|
||||
return chunk.split(URL_REGEX)
|
||||
.filter(urlChunk => !!urlChunk)
|
||||
.map((urlChunk, index) => {
|
||||
if (urlChunk.match(URL_REGEX)) {
|
||||
return ( <a className='link' href={urlChunk} key={index} target='_blank' rel='noopener noreferrer'>{urlChunk}</a> );
|
||||
}
|
||||
|
||||
return urlChunk;
|
||||
});
|
||||
}
|
||||
|
||||
function parseMentionChunk(chunk) {
|
||||
return chunk.split(MENTION_REGEX)
|
||||
.filter(mentionChunk => !!mentionChunk)
|
||||
.map((mentionChunk, index) => {
|
||||
const mention = mentionChunk.match(MENTION_REGEX);
|
||||
|
||||
if (mention) {
|
||||
const name = mention[0].substr(1);
|
||||
return ( <PlayerLink name={name} label={mention} key={index} /> );
|
||||
}
|
||||
|
||||
return mentionChunk;
|
||||
});
|
||||
}
|
||||
|
||||
export default Message;
|
||||
Reference in New Issue
Block a user