Webatrice: card import wizard (#4397)

This commit is contained in:
Jeremy Letto
2021-10-14 20:42:35 -05:00
committed by GitHub
parent dde0f568d9
commit 36e5a399d5
41 changed files with 1479 additions and 35 deletions

View File

@@ -0,0 +1,4 @@
.callout {
font-weight: bold;
color: green;
}

View 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;

View File

@@ -0,0 +1,3 @@
.link {
color: blue;
}

View 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;