Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 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 Down Expand Up @@ -127,6 +128,9 @@
"react-scripts": "^5.0.1",
"react-toastify": "^9.1.3",
"react-use": "^17.5.1",
"rehype-raw": "^7.0.0",
"rehype-sanitize": "^6.0.0",
"remark-gfm": "^3.0.1",
"styled-components": "^5.3.3",
"subgraph-status": "^1.2.4",
"viem": "^2.24.1",
Expand Down
17 changes: 9 additions & 8 deletions web/src/components/DisputePreview/DisputeContext.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import React, { useMemo } from "react";
import styled from "styled-components";

import { DisputeDetails } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes";
import { useAccount } from "wagmi";

import { DisputeDetails } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes";

import { INVALID_DISPUTE_DATA_ERROR, RPC_ERROR } from "consts/index";
import { Answer as IAnswer } from "context/NewDisputeContext";
import { isUndefined } from "utils/index";

import { responsiveSize } from "styles/responsiveSize";

import { DisputeDetailsQuery, VotingHistoryQuery } from "src/graphql/graphql";

import ReactMarkdown from "components/ReactMarkdown";
import { responsiveSize } from "styles/responsiveSize";

import MarkdownRenderer from "components/MarkdownRenderer";
import { StyledSkeleton } from "components/StyledSkeleton";

import CardLabel from "../DisputeView/CardLabels";
import { Divider } from "../Divider";
import { ExternalLink } from "../ExternalLink";
import RulingAndRewardsIndicators from "../Verdict/RulingAndRewardsIndicators";

import AliasDisplay from "./Alias";
import RulingAndRewardsIndicators from "../Verdict/RulingAndRewardsIndicators";
import CardLabel from "../DisputeView/CardLabels";

const StyledH1 = styled.h1`
margin: 0;
Expand Down Expand Up @@ -134,12 +135,12 @@ export const DisputeContext: React.FC<IDisputeContext> = ({
<div>
{disputeDetails?.question?.trim() ? (
<ReactMarkdownWrapper dir="auto">
<ReactMarkdown>{disputeDetails.question}</ReactMarkdown>
<MarkdownRenderer content={disputeDetails.question} />
</ReactMarkdownWrapper>
) : null}
{disputeDetails?.description?.trim() ? (
<ReactMarkdownWrapper dir="auto">
<ReactMarkdown>{disputeDetails.description}</ReactMarkdown>
<MarkdownRenderer content={disputeDetails.description} />
</ReactMarkdownWrapper>
) : null}
</div>
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
170 changes: 170 additions & 0 deletions web/src/components/ExternalLinkWarning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
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;
max-height: 90vh;
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;
overflow-y: auto;
`;

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