diff --git a/web/src/components/Verdict/Answer.tsx b/web/src/components/Verdict/Answer.tsx index 47d17b66b..fe03b6b66 100644 --- a/web/src/components/Verdict/Answer.tsx +++ b/web/src/components/Verdict/Answer.tsx @@ -1,17 +1,8 @@ import React from "react"; -import styled from "styled-components"; import { Answer } from "@kleros/kleros-sdk/src/dataMappings/utils/disputeDetailsTypes"; -import { AnswerDescription, AnswerTitle, AnswerTitleAndDescription } from "../DisputePreview/DisputeContext"; - -const Container = styled.div` - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-items: center; - gap: 6px; -`; +import { AnswerTitle, AnswerTitleAndDescription } from "../DisputePreview/DisputeContext"; interface IAnswer { answer?: Answer; @@ -24,12 +15,11 @@ const AnswerDisplay: React.FC = ({ answer, currentRuling }) => { {answer ? ( {answer.title} - {answer.description.trim() ? ` - ${answer.description}` : null} ) : ( - + {currentRuling !== 0 ? Answer 0x{currentRuling} : Refuse to Arbitrate} - + )} ); diff --git a/web/src/components/Verdict/FinalDecision.tsx b/web/src/components/Verdict/FinalDecision.tsx index f2a25320d..3191c53c8 100644 --- a/web/src/components/Verdict/FinalDecision.tsx +++ b/web/src/components/Verdict/FinalDecision.tsx @@ -33,15 +33,15 @@ const Container = styled.div` const JuryContainer = styled.div` display: flex; - flex-direction: row; - flex-wrap: wrap; align-items: center; gap: 5px 7px; - flex: 1; + flex-wrap: wrap; + h3 { line-height: 21px; margin-bottom: 0px; } + > div { flex: 1; } diff --git a/web/src/pages/Courts/CourtDetails/TopSearch.tsx b/web/src/pages/Courts/CourtDetails/TopSearch.tsx new file mode 100644 index 000000000..fed78ae7e --- /dev/null +++ b/web/src/pages/Courts/CourtDetails/TopSearch.tsx @@ -0,0 +1,166 @@ +import React, { useState, useMemo } from "react"; +import styled, { css } from "styled-components"; + +import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; +import { useNavigate, useParams } from "react-router-dom"; + +import { Card, DropdownCascader, Searchbar } from "@kleros/ui-components-library"; + +import { isUndefined } from "utils/index"; + +import { useCourtTree, rootCourtToItems } from "queries/useCourtTree"; + +import { isKlerosUniversity } from "src/consts"; + +import { hoverShortTransitionTiming } from "styles/commonStyles"; +import { landscapeStyle } from "styles/landscapeStyle"; +import { responsiveSize } from "styles/responsiveSize"; + +import { StyledSkeleton } from "components/StyledSkeleton"; + +import StakeMaintenanceButtons from "../StakeMaintenanceButton"; + +const Container = styled.div` + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px 16px; + flex-wrap: wrap; +`; + +const StyledDropdownCascader = styled(DropdownCascader)` + width: ${responsiveSize(200, 240)}; + > button { + width: 100%; + } +`; + +const SearchBarContainer = styled.div` + display: flex; + flex-wrap: wrap; + position: relative; + ${landscapeStyle( + () => css` + flex: 1; + ` + )} +`; + +const StyledSearchbar = styled(Searchbar)` + width: 100%; + input { + font-size: 16px; + height: 45px; + padding-top: 0px; + padding-bottom: 0px; + } +`; + +const SearchResultsContainer = styled(OverlayScrollbarsComponent)` + position: absolute; + margin-top: 45px; + max-height: 400px; + border: 1px solid ${({ theme }) => theme.stroke}; + width: 100%; + flex-direction: column; + border-radius: 4px; + overflow-y: auto; + z-index: 1; + background-color: ${({ theme }) => theme.whiteBackground}; +`; + +const StyledCard = styled(Card)<{ selected: boolean }>` + ${hoverShortTransitionTiming} + height: auto; + width: 100%; + padding: ${({ selected }) => (selected ? "16px 13px" : "16px")}; + cursor: pointer; + border: none; + border-left: ${({ selected, theme }) => (selected ? `3px solid ${theme.primaryBlue}` : "none")}; + background-color: ${({ selected, theme }) => (selected ? theme.mediumBlue : "transparent")}; + + :hover { + background-color: ${({ theme }) => theme.mediumBlue}; + } +`; + +const CourtParentSpan = styled.span` + color: ${({ theme }) => theme.secondaryText}EE; +`; + +const CourtNameSpan = styled.span` + color: ${({ theme }) => theme.primaryText}; +`; + +function flattenCourts(court, parent = null) { + const current = { + ...court, + parentName: parent?.name ?? null, + }; + const children = (court.children || []).flatMap((child) => flattenCourts(child, current)); + return [current, ...children]; +} + +const TopSearch: React.FC = () => { + const { data } = useCourtTree(); + const navigate = useNavigate(); + const { id: currentCourtId } = useParams(); + const items = useMemo(() => !isUndefined(data) && [rootCourtToItems(data.court)], [data]); + const isUniversity = isKlerosUniversity(); + const [search, setSearch] = useState(""); + + const filteredCourts = useMemo(() => { + if (!data?.court) return []; + const courts = flattenCourts(data.court).filter((c) => c.name.toLowerCase().includes(search.toLowerCase())); + const selectedCourt = courts.find((c) => c.id === currentCourtId); + if (!selectedCourt) return courts; + + return [selectedCourt, ...courts.filter((c) => c.id !== currentCourtId)]; + }, [data, search, currentCourtId]); + + return ( + + {items ? ( + <> + navigate(path.toString())} + placeholder="Select Court" + /> + + setSearch(e.target.value)} + /> + {search && filteredCourts.length > 0 && ( + + {filteredCourts.map((court) => ( + { + navigate(`/courts/${court.id}`); + setSearch(""); + }} + > + {court.parentName && {court.parentName} / } + {court.name} + + ))} + + )} + + + ) : ( + + )} + {isUniversity ? null : } + + ); +}; + +export default TopSearch; diff --git a/web/src/pages/Courts/CourtDetails/index.tsx b/web/src/pages/Courts/CourtDetails/index.tsx index fd3f3d610..a72802353 100644 --- a/web/src/pages/Courts/CourtDetails/index.tsx +++ b/web/src/pages/Courts/CourtDetails/index.tsx @@ -25,6 +25,7 @@ import { Divider } from "components/Divider"; import Description from "./Description"; import StakePanel from "./StakePanel"; import Stats from "./Stats"; +import TopSearch from "./TopSearch"; const Container = styled.div``; @@ -113,6 +114,7 @@ const CourtDetails: React.FC = () => { return ( + diff --git a/web/src/pages/Courts/TopSearch.tsx b/web/src/pages/Courts/TopSearch.tsx deleted file mode 100644 index bc933f312..000000000 --- a/web/src/pages/Courts/TopSearch.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React, { useMemo } from "react"; -import styled from "styled-components"; - -import { useNavigate } from "react-router-dom"; - -import { DropdownCascader } from "@kleros/ui-components-library"; - -import { isUndefined } from "utils/index"; - -import { useCourtTree, rootCourtToItems } from "queries/useCourtTree"; - -import { responsiveSize } from "styles/responsiveSize"; - -import { StyledSkeleton } from "components/StyledSkeleton"; - -import StakeMaintenanceButtons from "./StakeMaintenanceButton"; -import { isKlerosUniversity } from "src/consts"; - -const Container = styled.div` - width: 100%; - display: flex; - justify-content: space-between; - align-items: center; -`; - -const StyledDropdownCascader = styled(DropdownCascader)` - width: ${responsiveSize(200, 240)}; - > button { - width: 100%; - } -`; - -const TopSearch: React.FC = () => { - const { data } = useCourtTree(); - const navigate = useNavigate(); - const items = useMemo(() => !isUndefined(data) && [rootCourtToItems(data.court)], [data]); - const isUniversity = isKlerosUniversity(); - return ( - - {items ? ( - navigate(path.toString())} - placeholder="Select Court" - /> - ) : ( - - )} - {isUniversity ? null : } - - ); -}; - -export default TopSearch; diff --git a/web/src/pages/Courts/index.tsx b/web/src/pages/Courts/index.tsx index fb0419bcc..1efa1abee 100644 --- a/web/src/pages/Courts/index.tsx +++ b/web/src/pages/Courts/index.tsx @@ -7,7 +7,6 @@ import { responsiveSize } from "styles/responsiveSize"; import { Routes, Route, Navigate } from "react-router-dom"; import CourtDetails from "./CourtDetails"; -import TopSearch from "./TopSearch"; const Container = styled.div` width: 100%; @@ -26,7 +25,6 @@ const Container = styled.div` const Courts: React.FC = () => { return ( - } /> } />