import { observer } from "mobx-react-lite"; import { Col, Row } from "reactstrap"; import { useTranslation } from "react-i18next"; import { sprintf } from "sprintf-js"; import { sanitize } from "dompurify"; import { useSiteStore } from "src/Stores"; import { AbilitySiteYell, CommentSiteYell, InviteSiteYell, LevelSiteYell, OnSiteYellInput, SiteYell, TVSiteYell, } from "src/site/Site"; import { formatText, getAbilityUpText, getGenreText, getHitPointsClass, } from "src/Utility"; import AvatarDrawing from "src/AvatarDrawing"; import AvatarTitle from "src/AvatarTitle"; import { ReactComponent } from "src/assets/TwitchGlitchPurple.svg"; import scss from "src/site/SiteYellItem.module.scss"; import SiteComponent from "src/site/SiteComponent"; const EventPB = require("src/Event_pb"); export default observer( ({ data, onSiteYellInput, }: { data: SiteYell; onSiteYellInput: OnSiteYellInput; }) => { const { siteYellVariety, date, avatarID, avatarName, siteYell } = data; const { saveTraffic } = useSiteStore(); const { t } = useTranslation(); const doSiteYell = (siteYell: string) => { siteYell = siteYell.replace(" ", " "); const m = siteYell.match(/(http|https|mailto|rtmp):\/\/[^ ]+/i); if (m != null) { const t = m[0]; if ( !saveTraffic && t.match(/(\.aac|\.flac|\.mid|\.midi|\.mp3|\.ogg|\.wav|\.wma)($|\?)/i) ) { return siteYell.replace( t, `<audio class="${scss.file}" src="${t}" controls></audio>`, ); } if ( !saveTraffic && t.match(/(\.bmp|\.gif|\.heic|\.jpeg|\.jpg|\.png|\.webp)($|\?)/i) ) { return siteYell.replace( t, `<a href="${t}" target="_blank"> <img class="${scss.file}" src="${t}" alt=""> </a>`, ); } if ( !saveTraffic && t.match(/(\.avi|\.mkv|\.mp4|\.mpeg|\.mpg|\.wmv)($|\?)/i) ) { return siteYell.replace( t, `<video class="${scss.file}" src="${t}" controls></video>`, ); } return siteYell.replace(t, `<a href="${t}" target="_blank">${t}</a>`); } return siteYell; }; switch (siteYellVariety) { case "@Enter": return ( <Row className="g-0" style={{ flexWrap: "nowrap" }} onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && ( <Col className="m-1" xs="auto"> <AvatarDrawing avatarID={avatarID} /> </Col> )} <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span className={scss.enter}>{t("siteYellEnter")}</span> </Col> </Row> ); case "@Quit": return ( <Row className="g-0" style={{ flexWrap: "nowrap" }} onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && ( <Col className="m-1" xs="auto"> <AvatarDrawing avatarID={avatarID} /> </Col> )} <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span className={scss.quit}>{t("siteYellQuit")}</span> </Col> </Row> ); case "@Site": return ( <Row className="g-0" style={{ flexWrap: "nowrap" }} onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && ( <Col className="m-1" xs="auto"> <AvatarDrawing avatarID={avatarID} /> </Col> )} <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span className={scss.enter}>{t("siteYellNewSite")}</span> </Col> </Row> ); case "@Net": return ( <Row className="g-0" style={{ flexWrap: "nowrap" }} onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && ( <Col className="m-1" xs="auto"> <AvatarDrawing avatarID={avatarID} /> </Col> )} <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span className={scss.enter}>{t("siteYellNewNetSite")}</span> </Col> </Row> ); case "@Notify": return ( <Row className="g-0" style={{ flexWrap: "nowrap" }}> <Col className="m-1" xs="auto"> <span className="taehui">{t("siteYellTaehui")}</span>{" "} <span className="date">{date}</span> <br /> <span dangerouslySetInnerHTML={{ __html: doSiteYell(siteYell as string), }} /> </Col> </Row> ); case "@Invite": { const { siteID, siteName, avatarName } = siteYell as InviteSiteYell; return ( <Row className="g-0" style={{ flexWrap: "nowrap" }} onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && ( <Col className="m-1" xs="auto"> <AvatarDrawing avatarID={avatarID} /> </Col> )} <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span className="route" onClick={() => { SiteComponent.send({ eventID: EventPB.Event.EventID.ENTER_SITE, text: JSON.stringify({ siteID, siteCipher: "", }), }); }} > {sprintf(t("siteYellInvite"), siteName)} </span> </Col> </Row> ); } case "@TV": const { href, title, text } = siteYell as TVSiteYell; return ( <Row className="g-0" style={{ flexWrap: "nowrap" }}> <Col className="m-1" xs="auto"> <ReactComponent className={scss.tv} /> </Col> <Col className="m-1" xs="auto"> <span>{text}</span> <span className="date">{date}</span> <br /> <span className="route" onClick={() => { window.open(href); }} > {sprintf(t("siteYellTV"), title)} </span> </Col> </Row> ); case "@Wiped": return ( <Row className="g-0" style={{ flexWrap: "nowrap" }}> <Col className="m-1" xs="auto" onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && <AvatarDrawing avatarID={avatarID} />} </Col> <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span>{t("wipedSiteYell")}</span> </Col> </Row> ); case "@Comment": { const { avatarID, avatarName, title, artist, genre, level, levelText, stand, hitPointsMode, } = siteYell as CommentSiteYell; return ( <Row className="g-0" style={{ flexWrap: "nowrap" }} onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && ( <Col className="m-1" xs="auto"> <AvatarDrawing avatarID={avatarID} /> </Col> )} <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span className={`level${level}`}>{levelText}</span>{" "} <span className="artist">{artist}</span>{" "} <span className="title">{title}</span>{" "} <span className="genre">{getGenreText(genre)}</span> <br /> <span className={getHitPointsClass(hitPointsMode)}> {sprintf(t("textStand"), formatText(stand))} </span> </Col> </Row> ); } case "@Ability": { const { avatarID, avatarName } = siteYell as AbilitySiteYell; return ( <Row className="g-0" style={{ flexWrap: "nowrap" }} onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && ( <Col className="m-1" xs="auto"> <AvatarDrawing avatarID={avatarID} /> </Col> )} <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span>{getAbilityUpText(t, siteYell as AbilitySiteYell)}</span> <br /> </Col> </Row> ); } case "@Level": { const { avatarID, avatarName, title } = siteYell as LevelSiteYell; return ( <Row className="g-0" style={{ flexWrap: "nowrap" }} onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && ( <Col className="m-1" xs="auto"> <AvatarDrawing avatarID={avatarID} /> </Col> )} <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span>{sprintf(t("wwwLevelClearText"), title)}</span> <br /> </Col> </Row> ); } case "": return ( <> <span>{siteYell as string}</span> <br /> </> ); case null: return ( <Row className="g-0" style={{ flexWrap: "nowrap" }}> <Col className="m-1" xs="auto" onContextMenu={(e) => { e.preventDefault(); avatarID && onSiteYellInput && onSiteYellInput(e, avatarID); }} > {avatarID && <AvatarDrawing avatarID={avatarID} />} </Col> <Col className="m-1" xs="auto"> {avatarID && <AvatarTitle avatarID={avatarID} />} <span>{avatarName}</span> <span className="date">{date}</span> <br /> <span dangerouslySetInnerHTML={{ __html: doSiteYell(sanitize(siteYell as string)), }} /> </Col> </Row> ); default: return null; } }, );