Add link modal and fix input (#67)
This commit is contained in:
parent
2a38552281
commit
7bb7f059b8
|
@ -56,7 +56,7 @@ export function ChatInput({ theme, addMessage }: ChatInputProps) {
|
||||||
setContent("");
|
setContent("");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[]
|
[content, imageUint]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -15,12 +15,14 @@ type ChatMessageContentProps = {
|
||||||
message: ChatMessage;
|
message: ChatMessage;
|
||||||
fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
|
fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
|
||||||
setImage: (image: string) => void;
|
setImage: (image: string) => void;
|
||||||
|
setLinkOpen: (link: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ChatMessageContent({
|
export function ChatMessageContent({
|
||||||
message,
|
message,
|
||||||
fetchMetadata,
|
fetchMetadata,
|
||||||
setImage,
|
setImage,
|
||||||
|
setLinkOpen,
|
||||||
}: ChatMessageContentProps) {
|
}: ChatMessageContentProps) {
|
||||||
const { content, image } = useMemo(() => message, [message]);
|
const { content, image } = useMemo(() => message, [message]);
|
||||||
const [elements, setElements] = useState<(string | React.ReactElement)[]>([
|
const [elements, setElements] = useState<(string | React.ReactElement)[]>([
|
||||||
|
@ -40,7 +42,7 @@ export function ChatMessageContent({
|
||||||
? match
|
? match
|
||||||
: "https://" + match;
|
: "https://" + match;
|
||||||
newSplit.push(
|
newSplit.push(
|
||||||
<Link key={idx} href={link} target="_blank" rel="noopener noreferrer">
|
<Link key={idx} onClick={() => setLinkOpen(link)}>
|
||||||
{match}
|
{match}
|
||||||
</Link>,
|
</Link>,
|
||||||
split[idx + 1]
|
split[idx + 1]
|
||||||
|
@ -88,9 +90,7 @@ export function ChatMessageContent({
|
||||||
</MessageImageWrapper>
|
</MessageImageWrapper>
|
||||||
)}
|
)}
|
||||||
{openGraph && (
|
{openGraph && (
|
||||||
<PreviewWrapper
|
<PreviewWrapper onClick={() => setLinkOpen(link ?? "")}>
|
||||||
onClick={() => window?.open(link, "_blank", "noopener")?.focus()}
|
|
||||||
>
|
|
||||||
<PreviewImage src={decodeURI(decode(openGraph["og:image"]))} />
|
<PreviewImage src={decodeURI(decode(openGraph["og:image"]))} />
|
||||||
<PreviewTitleWrapper>{openGraph["og:title"]}</PreviewTitleWrapper>
|
<PreviewTitleWrapper>{openGraph["og:title"]}</PreviewTitleWrapper>
|
||||||
<PreviewSiteNameWrapper>
|
<PreviewSiteNameWrapper>
|
||||||
|
@ -167,7 +167,7 @@ const ContentWrapper = styled.div`
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Link = styled.a`
|
const Link = styled.div`
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: ${({ theme }) => theme.memberNameColor};
|
color: ${({ theme }) => theme.memberNameColor};
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { ChatMessage } from "../../models/ChatMessage";
|
||||||
import { Metadata } from "../../models/Metadata";
|
import { Metadata } from "../../models/Metadata";
|
||||||
import { LoadingIcon } from "../Icons/LoadingIcon";
|
import { LoadingIcon } from "../Icons/LoadingIcon";
|
||||||
import { UserIcon } from "../Icons/UserIcon";
|
import { UserIcon } from "../Icons/UserIcon";
|
||||||
|
import { LinkModal } from "../Modals/LinkModal";
|
||||||
import { PictureModal } from "../Modals/PictureModal";
|
import { PictureModal } from "../Modals/PictureModal";
|
||||||
import { textSmallStyles } from "../Text";
|
import { textSmallStyles } from "../Text";
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ export function ChatMessages({
|
||||||
}, [ref, scrollOnBot]);
|
}, [ref, scrollOnBot]);
|
||||||
|
|
||||||
const [image, setImage] = useState("");
|
const [image, setImage] = useState("");
|
||||||
|
const [link, setLink] = useState("");
|
||||||
return (
|
return (
|
||||||
<MessagesWrapper ref={ref}>
|
<MessagesWrapper ref={ref}>
|
||||||
<PictureModal
|
<PictureModal
|
||||||
|
@ -61,6 +62,7 @@ export function ChatMessages({
|
||||||
onClose={() => setImage("")}
|
onClose={() => setImage("")}
|
||||||
image={image}
|
image={image}
|
||||||
/>
|
/>
|
||||||
|
<LinkModal isVisible={!!link} onClose={() => setLink("")} link={link} />
|
||||||
<LoadingWrapper>
|
<LoadingWrapper>
|
||||||
<LoadingIcon className="message" />
|
<LoadingIcon className="message" />
|
||||||
</LoadingWrapper>
|
</LoadingWrapper>
|
||||||
|
@ -93,6 +95,7 @@ export function ChatMessages({
|
||||||
message={message}
|
message={message}
|
||||||
fetchMetadata={fetchMetadata}
|
fetchMetadata={fetchMetadata}
|
||||||
setImage={setImage}
|
setImage={setImage}
|
||||||
|
setLinkOpen={setLink}
|
||||||
/>
|
/>
|
||||||
</MessageText>
|
</MessageText>
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import { textMediumStyles } from "../Text";
|
||||||
|
|
||||||
|
import { BasicModalProps, Modal } from "./Modal";
|
||||||
|
|
||||||
|
interface LinkModalProps extends BasicModalProps {
|
||||||
|
link: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LinkModal = ({ isVisible, onClose, link }: LinkModalProps) => {
|
||||||
|
return (
|
||||||
|
<Modal isVisible={isVisible} onClose={onClose}>
|
||||||
|
<Section>
|
||||||
|
<Text>Are you sure you want to visit {link}</Text>
|
||||||
|
</Section>
|
||||||
|
<ButtonSection>
|
||||||
|
<ButtonNo onClick={onClose}>No</ButtonNo>
|
||||||
|
<ButtonYes
|
||||||
|
onClick={() => {
|
||||||
|
window?.open(link, "_blank", "noopener")?.focus();
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Yes
|
||||||
|
</ButtonYes>
|
||||||
|
</ButtonSection>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ButtonSection = styled.div`
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Section = styled.div`
|
||||||
|
padding: 20px 16px;
|
||||||
|
|
||||||
|
& + & {
|
||||||
|
border-top: 1px solid ${({ theme }) => theme.border};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Text = styled.p`
|
||||||
|
color: ${({ theme }) => theme.primary};
|
||||||
|
|
||||||
|
${textMediumStyles}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ButtonYes = styled.button`
|
||||||
|
background-color: ${({ theme }) => theme.tertiary};
|
||||||
|
padding: 10px;
|
||||||
|
width: 50px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ButtonNo = styled.button`
|
||||||
|
background-color: ${({ theme }) => theme.secondary};
|
||||||
|
padding: 10px;
|
||||||
|
width: 50px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
`;
|
Loading…
Reference in New Issue