diff --git a/web/package.json b/web/package.json index ae91ad5..fd7f035 100644 --- a/web/package.json +++ b/web/package.json @@ -73,7 +73,7 @@ }, "dependencies": { "@filebase/client": "^0.0.5", - "@kleros/ui-components-library": "^2.6.3", + "@kleros/ui-components-library": "^2.7.1", "@sentry/react": "^7.93.0", "@sentry/tracing": "^7.93.0", "@supabase/supabase-js": "^2.39.3", diff --git a/web/src/app.tsx b/web/src/app.tsx index 1011e58..44a4955 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -11,6 +11,8 @@ import RefetchOnBlock from "context/RefetchOnBlock"; import Layout from "layout/index"; import Home from "./pages/Home"; import AllLists from "./pages/AllLists"; +import SubmitItem from "./pages/SubmitItem"; +import { SubmitItemProvider } from "./context/SubmitItemContext"; const App: React.FC = () => { return ( @@ -19,13 +21,16 @@ const App: React.FC = () => { - - }> - } /> - } /> - 404 not found} /> - - + + + }> + } /> + } /> + } /> + 404 not found} /> + + + diff --git a/web/src/assets/svgs/icons/etherscan.svg b/web/src/assets/svgs/icons/etherscan.svg new file mode 100644 index 0000000..776c369 --- /dev/null +++ b/web/src/assets/svgs/icons/etherscan.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/web/src/assets/svgs/icons/globe.svg b/web/src/assets/svgs/icons/globe.svg new file mode 100644 index 0000000..5f565ba --- /dev/null +++ b/web/src/assets/svgs/icons/globe.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/svgs/icons/history.svg b/web/src/assets/svgs/icons/history.svg new file mode 100644 index 0000000..751a6a4 --- /dev/null +++ b/web/src/assets/svgs/icons/history.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/web/src/assets/svgs/icons/plus.svg b/web/src/assets/svgs/icons/plus.svg new file mode 100644 index 0000000..16d74e8 --- /dev/null +++ b/web/src/assets/svgs/icons/plus.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/web/src/components/ChainIcon.tsx b/web/src/components/ChainIcon.tsx index e24fa45..d37fea1 100644 --- a/web/src/components/ChainIcon.tsx +++ b/web/src/components/ChainIcon.tsx @@ -6,7 +6,7 @@ import PolygonIcon from "svgs/chains/polygon.svg"; import GnosisIcon from "svgs/chains/gnosis.svg"; import styled from "styled-components"; -const getChainIcon = (chainId: number) => { +export const getChainIcon = (chainId: number) => { switch (chainId) { case mainnet.id: case sepolia.id: @@ -25,6 +25,25 @@ const getChainIcon = (chainId: number) => { } }; +export const getChainName = (chainId: number) => { + switch (chainId) { + case mainnet.id: + case sepolia.id: + return "Ethereum"; + case arbitrum.id: + case arbitrumSepolia.id: + return "Arbitrum"; + case gnosis.id: + case gnosisChiado.id: + return "Gnosis"; + case polygon.id: + case polygonMumbai.id: + return "Polygon"; + default: + return "Ethereum"; + } +}; + const SVGContainer = styled.div` display: flex; align-items: center; diff --git a/web/src/components/HistoryDisplay/Header.tsx b/web/src/components/HistoryDisplay/Header.tsx new file mode 100644 index 0000000..1ca4717 --- /dev/null +++ b/web/src/components/HistoryDisplay/Header.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import styled from "styled-components"; +import HistoryIcon from "assets/svgs/icons/history.svg"; + +const HeaderContainer = styled.div` + display: flex; + gap: 8px; +`; + +const StyledP = styled.p` + margin: 0; + color: ${({ theme }) => theme.primaryText}; +`; + +const SVGContainer = styled.div` + display: flex; + align-items: center; + justify-content: center; + svg { + fill: ${({ theme }) => theme.primaryText}; + height: 16px; + width: 17px; + } +`; +const Header: React.FC = () => { + return ( + + + + + History + + ); +}; + +export default Header; diff --git a/web/src/components/HistoryDisplay/index.tsx b/web/src/components/HistoryDisplay/index.tsx new file mode 100644 index 0000000..733b396 --- /dev/null +++ b/web/src/components/HistoryDisplay/index.tsx @@ -0,0 +1,33 @@ +import { Card, CustomTimeline, _TimelineItem1 as TimelineItem } from "@kleros/ui-components-library"; +import React from "react"; +import styled from "styled-components"; +import Header from "./Header"; + +const Container = styled(Card)` + display: flex; + width: 100%; + height: auto; + flex-direction: column; + align-items: start; + padding: 22px 32px; + gap: 54px; +`; + +const StyledTimeline = styled(CustomTimeline)` + width: 100%; + margin-bottom: 30px; +`; + +interface IHistory { + items: TimelineItem[]; +} + +const History: React.FC = ({ items }) => { + return ( + +
+ + + ); +}; +export default History; diff --git a/web/src/components/InformationCard/Policies.tsx b/web/src/components/InformationCard/Policies.tsx new file mode 100644 index 0000000..5549344 --- /dev/null +++ b/web/src/components/InformationCard/Policies.tsx @@ -0,0 +1,80 @@ +import React from "react"; +import styled, { css } from "styled-components"; +import { landscapeStyle } from "styles/landscapeStyle"; +import PolicyIcon from "svgs/icons/policy.svg"; +import { responsiveSize } from "styles/responsiveSize"; +// import { getIpfsUrl } from "utils/getIpfsUrl"; + +const ShadeArea = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + width: 100%; + padding: ${responsiveSize(16, 20)} ${responsiveSize(16, 32)}; + margin-top: 16px; + background-color: ${({ theme }) => theme.mediumBlue}; + + ${landscapeStyle( + () => css` + flex-direction: row; + justify-content: space-between; + ` + )}; +`; + +const StyledP = styled.p` + font-size: 14px; + margin-top: 0; + margin-bottom: 16px; + color: ${({ theme }) => theme.primaryBlue}; + ${landscapeStyle( + () => css` + margin-bottom: 0; + ` + )}; +`; + +const StyledA = styled.a` + display: flex; + align-items: center; + gap: 4px; +`; + +const StyledPolicyIcon = styled(PolicyIcon)` + width: 16px; + fill: ${({ theme }) => theme.primaryBlue}; +`; + +const LinkContainer = styled.div` + display: flex; + gap: ${responsiveSize(16, 24)}; + flex-wrap: wrap; +`; + +type Attachment = { + label?: string; + uri: string; +}; +interface IPolicies { + disputePolicyURI?: string; + courtId?: string; + attachment?: Attachment; +} + +export const Policies: React.FC = ({ disputePolicyURI, courtId, attachment }) => { + return ( + + Make sure you read and understand the Policies + + + + Curation Policy + + + + List Policy + + + + ); +}; diff --git a/web/src/components/InformationCard/index.tsx b/web/src/components/InformationCard/index.tsx new file mode 100644 index 0000000..c46e88b --- /dev/null +++ b/web/src/components/InformationCard/index.tsx @@ -0,0 +1,175 @@ +import React from "react"; +import styled from "styled-components"; +import { responsiveSize } from "styles/responsiveSize"; +import { useToggle } from "react-use"; +import { Button, Card } from "@kleros/ui-components-library"; +import { getChainIcon, getChainName } from "components/ChainIcon"; +import { getStatusColor, getStatusLabel } from "components/RegistryCard/StatusBanner"; +import AliasDisplay from "components/RegistryInfo/AliasDisplay"; +import { Policies } from "./Policies"; +import EtherscanIcon from "svgs/icons/etherscan.svg"; +import { Status } from "consts/status"; +import RemoveModal from "../Modal/RemoveModal"; + +const StyledCard = styled(Card)` + display: flex; + width: 100%; + height: auto; + flex-direction: column; + margin-bottom: 64px; +`; + +const StatusContainer = styled.div<{ status: Status; isList: boolean }>` + display: flex; + margin-top: 18px; + .dot { + ::before { + content: ""; + display: inline-block; + height: 8px; + width: 8px; + border-radius: 50%; + margin-right: 8px; + } + } + ${({ theme, status }) => { + const [frontColor] = getStatusColor(status, theme); + return ` + .front-color { + color: ${frontColor}; + } + .dot { + ::before { + background-color: ${frontColor}; + } + } + `; + }}; +`; + +const TopInfo = styled.div` + display: flex; + justify-content: space-between; + flex-wrap: wrap; + gap: 12px; + padding: 12px 32px; +`; + +const LogoAndTitle = styled.div` + display: flex; + align-items: center; +`; + +const TopLeftInfo = styled.div` + display: flex; + flex-direction: column; +`; + +const TopRightInfo = styled.div` + display: flex; + flex-direction: row; + gap: 48px; +`; + +const ChainContainer = styled.div` + display: flex; + gap: 8px; + align-items: top; + justify-content: center; +`; + +const StyledEtherscanIcon = styled(EtherscanIcon)` + display: flex; + height: 16px; + width: 16px; + margin-top: 20px; +`; + +const StyledLogo = styled.img<{ isList: boolean }>` + width: ${({ isList }) => (isList ? "48px" : "125px")}; + height: ${({ isList }) => (isList ? "48px" : "125px")}; + object-fit: contain; + margin-bottom: ${({ isList }) => (isList ? "0px" : "8px")}; +`; + +const StyledP = styled.p` + color: ${({ theme }) => theme.secondaryText}; + margin: 0; +`; + +const Divider = styled.hr` + border: none; + height: 1px; + background-color: ${({ theme }) => theme.stroke}; + margin: ${responsiveSize(20, 28)} 32px; +`; + +const BottomInfo = styled.div` + display: flex; + padding: 0 32px; + padding-bottom: 12px; + flex-wrap: wrap; + gap: 12px; + justify-content: space-between; +`; + +interface IInformationCard { + title: string; + logoURI: string; + description: string; + chainId: number; + status: string; + isItem?: boolean; + // itemParams?: Object : item will have dynamic params +} + +const InformationCard: React.FC = ({ + title, + logoURI, + description, + chainId = 100, + status = Status.Included, + isItem = false, +}) => { + const [isRemoveListModalOpen, toggleRemoveListModal] = useToggle(false); + const [isRemoveItemModalOpen, toggleRemoveItemModal] = useToggle(false); + + return ( + <> + + + + + {!isItem && } +

{title}

+
+ {description} +
+ + +

{getChainIcon(chainId)}

+

{getChainName(chainId)}

+
+ + + + +
+
+ + + +