Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"@kleros/ui-components-library": "^2.20.0",
"@lifi/wallet-management": "^3.7.1",
"@lifi/widget": "^3.18.1",
"@mdxeditor/editor": "^3.45.0",
"@reown/appkit": "^1.7.1",
"@reown/appkit-adapter-wagmi": "^1.7.1",
"@sentry/react": "^7.120.0",
Expand All @@ -99,6 +100,7 @@
"@solana/wallet-adapter-react": "^0.15.36",
"@solana/web3.js": "^1.98.0",
"@tanstack/react-query": "^5.69.0",
"@types/dompurify": "^3.2.0",
"@types/react-modal": "^3.16.3",
"@wagmi/connectors": "^5.7.11",
"@wagmi/core": "^2.16.7",
Expand All @@ -107,6 +109,7 @@
"chartjs-adapter-moment": "^1.0.1",
"chartjs-plugin-datalabels": "^2.2.0",
"core-js": "^3.39.0",
"dompurify": "^3.2.6",
"ethers": "^5.8.0",
"graphql": "^16.9.0",
"graphql-request": "^7.1.2",
Expand Down
22 changes: 7 additions & 15 deletions web/src/components/EvidenceCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useMemo } from "react";
import styled, { css } from "styled-components";

import ReactMarkdown from "react-markdown";
import { useParams } from "react-router-dom";

import { Card } from "@kleros/ui-components-library";
Expand All @@ -18,9 +17,11 @@ import { hoverShortTransitionTiming } from "styles/commonStyles";
import { landscapeStyle } from "styles/landscapeStyle";
import { responsiveSize } from "styles/responsiveSize";

import JurorTitle from "pages/Home/TopJurors/JurorCard/JurorTitle";

import { ExternalLink } from "./ExternalLink";
import { InternalLink } from "./InternalLink";
import JurorTitle from "pages/Home/TopJurors/JurorCard/JurorTitle";
import MarkdownRenderer from "./MarkdownRenderer";

const StyledCard = styled(Card)`
width: 100%;
Expand Down Expand Up @@ -66,17 +67,6 @@ const Index = styled.p`
`;

const ReactMarkdownWrapper = styled.div``;
const StyledReactMarkdown = styled(ReactMarkdown)`
a {
font-size: 16px;
}
code {
color: ${({ theme }) => theme.secondaryText};
}
p {
margin: 0;
}
`;

const BottomShade = styled.div`
background-color: ${({ theme }) => theme.lightBlue};
Expand Down Expand Up @@ -227,10 +217,12 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
</IndexAndName>
{name && description ? (
<ReactMarkdownWrapper dir="auto">
<StyledReactMarkdown>{description}</StyledReactMarkdown>
<MarkdownRenderer content={description} />
</ReactMarkdownWrapper>
) : (
<p>{evidence}</p>
<ReactMarkdownWrapper dir="auto">
<MarkdownRenderer content={evidence} />
</ReactMarkdownWrapper>
)}
</TopContent>
<BottomShade>
Expand Down
168 changes: 168 additions & 0 deletions web/src/components/ExternalLinkWarning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import React from "react";
import styled, { css } from "styled-components";

import Modal from "react-modal";

import { Button } from "@kleros/ui-components-library";

import WarningIcon from "svgs/icons/warning-outline.svg";

import { landscapeStyle } from "styles/landscapeStyle";

const StyledModal = styled(Modal)`
position: absolute;
top: 50%;
left: 50%;
right: auto;
bottom: auto;
margin-right: -50%;
transform: translate(-50%, -50%);
height: auto;
width: min(90%, 480px);
border: 1px solid ${({ theme }) => theme.stroke};
border-radius: 8px;
background-color: ${({ theme }) => theme.whiteBackground};
padding: 32px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
z-index: 10002;
`;

const Overlay = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 10001;
`;

const Header = styled.div`
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
`;

const StyledWarningIcon = styled(WarningIcon)`
width: 24px;
height: 24px;
fill: ${({ theme }) => theme.warning};
`;

const Title = styled.h3`
color: ${({ theme }) => theme.primaryText};
font-size: 18px;
font-weight: 600;
margin: 0;
`;

const Message = styled.p`
color: ${({ theme }) => theme.primaryText};
font-size: 14px;
line-height: 1.5;
margin: 0 0 16px 0;
`;

const UrlContainer = styled.div`
background-color: ${({ theme }) => theme.lightGrey};
border: 1px solid ${({ theme }) => theme.stroke};
border-radius: 4px;
padding: 12px;
margin: 16px 0;
word-break: break-all;
`;

const Url = styled.code`
color: ${({ theme }) => theme.secondaryText};
font-size: 13px;
font-family: monospace;
`;

const ButtonContainer = styled.div`
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
margin-top: 24px;

${landscapeStyle(
() => css`
justify-content: flex-end;
`
)}
`;

const CancelButton = styled(Button)`
background-color: ${({ theme }) => theme.whiteBackground};
border: 1px solid ${({ theme }) => theme.stroke};

p {
color: ${({ theme }) => theme.primaryText} !important;
}

&:hover {
background-color: ${({ theme }) => theme.mediumBlue};
}
`;

const ConfirmButton = styled(Button)`
background-color: ${({ theme }) => theme.warning};
color: ${({ theme }) => theme.whiteBackground};
border: 1px solid ${({ theme }) => theme.warning};

&:hover {
background-color: ${({ theme }) => theme.warning}BB;
}
`;

interface IExternalLinkWarning {
isOpen: boolean;
url: string;
onConfirm: () => void;
onCancel: () => void;
}

const ExternalLinkWarning: React.FC<IExternalLinkWarning> = ({ isOpen, url, onConfirm, onCancel }) => {
return (
<StyledModal
isOpen={isOpen}
onRequestClose={onCancel}
overlayElement={(props, contentElement) => <Overlay {...props}>{contentElement}</Overlay>}
ariaHideApp={false}
role="dialog"
aria-labelledby="external-link-title"
aria-describedby="external-link-description"
>
<Header>
<StyledWarningIcon />
<Title id="external-link-title">External Link Warning</Title>
</Header>

<Message id="external-link-description">
You are about to navigate to an external website. Please verify the URL before proceeding to ensure it&apos;s
safe and legitimate.
</Message>

<UrlContainer>
<Url>{url}</Url>
</UrlContainer>

<Message>
<strong>Safety Tips:</strong>
<br />
• Verify the domain name is correct
<br />
• Check for suspicious characters or typos
<br />• Only proceed if you trust this destination
</Message>

<ButtonContainer>
<CancelButton text="Cancel" onClick={onCancel} />
<ConfirmButton text="Continue to External Site" onClick={onConfirm} />
</ButtonContainer>
</StyledModal>
);
};

export default ExternalLinkWarning;
23 changes: 7 additions & 16 deletions web/src/components/FileViewer/Viewers/MarkdownViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,14 @@ import React from "react";
import styled from "styled-components";

import { type DocRenderer } from "@cyntler/react-doc-viewer";
import ReactMarkdown from "react-markdown";

import MarkdownRenderer from "../../MarkdownRenderer";

const Container = styled.div`
padding: 16px;
`;

const StyledMarkdown = styled(ReactMarkdown)`
background-color: ${({ theme }) => theme.whiteBackground};
a {
font-size: 16px;
}
code {
color: ${({ theme }) => theme.secondaryText};
}
`;

const MarkdownRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {
const MarkdownDocRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {
if (!currentDocument) return null;
const base64String = (currentDocument.fileData as string).split(",")[1];

Expand All @@ -27,12 +18,12 @@ const MarkdownRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {

return (
<Container id="md-renderer">
<StyledMarkdown>{decodedData}</StyledMarkdown>
<MarkdownRenderer content={decodedData} />
</Container>
);
};

MarkdownRenderer.fileTypes = ["md", "text/plain"];
MarkdownRenderer.weight = 1;
MarkdownDocRenderer.fileTypes = ["md", "text/plain"];
MarkdownDocRenderer.weight = 1;

export default MarkdownRenderer;
export default MarkdownDocRenderer;
Loading
Loading