diff --git a/package.json b/package.json index 95283e46..661cbab6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@code4rena/components-library", - "version": "4.5.2", + "version": "4.5.3", "description": "Code4rena's official components library ", "types": "./dist/lib.d.ts", "exports": { diff --git a/src/lib/ContestStatus/AuditStatusSection.tsx b/src/lib/ContestStatus/AuditStatusSection.tsx new file mode 100644 index 00000000..54a6c335 --- /dev/null +++ b/src/lib/ContestStatus/AuditStatusSection.tsx @@ -0,0 +1,142 @@ +import React, { useEffect, useState } from "react"; +import { + AuditStatus, + MapAuditStatusToAuditPublicStage, +} from "./ContestStatus.types"; +import { getRelativeDateTimeLongFormat } from "../../utils/time"; +import { Icon } from "../Icon"; + +const getAuditStatusLabel = (status: AuditStatus | null) => { + switch (status) { + case AuditStatus.PreAudit: + return "Starts"; + case AuditStatus.Active: + return "Ends"; + case AuditStatus.Awarding: + return "Awarding"; + case AuditStatus.Judging: + return "Judging"; + case AuditStatus.PJQA: + return "Post-judging QA"; + case AuditStatus.Reporting: + return "Report in progress"; + case AuditStatus.Review: + return "Sponsor review"; + case AuditStatus.Triage: + return "Triage"; + case AuditStatus.Restricted: + return "Paused"; + case AuditStatus.JudgingComplete: + return "Judging"; + case AuditStatus.Paused: + return "Paused"; + case AuditStatus.Completed: + return "Completed"; + case AuditStatus.LostDeal: + case AuditStatus.Booking: + return null; + default: + return null; + } +}; + +const getAuditStatusColor = (status: AuditStatus | null) => { + switch (status) { + case AuditStatus.PreAudit: + return "#FFFFFF"; + case AuditStatus.Active: + return "#24c473"; // green-60 + case AuditStatus.Awarding: + case AuditStatus.Judging: + case AuditStatus.PJQA: + case AuditStatus.Reporting: + case AuditStatus.Review: + case AuditStatus.Triage: + return "#7549FF"; // blurple-60 + case AuditStatus.Restricted: + case AuditStatus.Paused: + return "#6B6680"; + case AuditStatus.JudgingComplete: + case AuditStatus.LostDeal: + case AuditStatus.Booking: + case AuditStatus.Completed: + return null; + default: + return null; + } +}; + +export const AuditStatusSection = ({ + auditStatus, + startTime, + endTime, +}: { + auditStatus: AuditStatus | null; + startTime: string; + endTime: string; +}) => { + // Get comparison time for relative time calculation + const [comparisonTime, setComparisonTime] = useState(null); + useEffect(() => { + if (auditStatus === AuditStatus.Active) { + setComparisonTime(new Date(endTime)); + } else if (auditStatus === AuditStatus.PreAudit) { + setComparisonTime(new Date(startTime)); + } else { + setComparisonTime(null); + } + }, [auditStatus, startTime, endTime]); + + // Get interval seconds for updating the relative time calculation + const [intervalSecs, setIntervalSecs] = useState(1); + useEffect(() => { + if (!endTime) return; + const endTimeDate = new Date(endTime); + const now = new Date(); + const diffMs = endTimeDate.getTime() - now.getTime(); + const oneHourMs = 3600000; + const halfHourSecs = 1800; + if (diffMs > oneHourMs) { + setIntervalSecs(halfHourSecs); + } else { + setIntervalSecs(1); + } + }, [endTime]); + + const [relativeDateTime, setRelativeDateTime] = useState(null); + useEffect(() => { + if (!comparisonTime) return; + const updateDateTime = () => { + const newRelativeDateTime = getRelativeDateTimeLongFormat(comparisonTime); + setRelativeDateTime(newRelativeDateTime); // Update relative date time string every interval + }; + const intervalId = setInterval(updateDateTime, intervalSecs); + updateDateTime(); + return () => clearInterval(intervalId); + }, [comparisonTime, intervalSecs]); + + if (!auditStatus) return null; + + const publicStage = MapAuditStatusToAuditPublicStage[auditStatus]; + + if (!publicStage) return null; + + const auditStatusLabel = getAuditStatusLabel(auditStatus); + const iconColor = getAuditStatusColor(auditStatus); + + return ( +
+ {iconColor && ( +
+ +
+ )} +
+ {auditStatusLabel} {relativeDateTime} +
+
+ ); +}; diff --git a/src/lib/ContestStatus/ContestStatus.scss b/src/lib/ContestStatus/ContestStatus.scss index 2f4b8468..9595e749 100644 --- a/src/lib/ContestStatus/ContestStatus.scss +++ b/src/lib/ContestStatus/ContestStatus.scss @@ -1,31 +1,33 @@ @import "../../styles/variables"; .c4conteststatus { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - gap: 0.75rem; - color: $color__white; - font-size: $font-size__text; - - .statusindicator { - width: $spacing__s; - height: $spacing__s; - border-radius: 50%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: 0.75rem; + color: $color__white; + font-size: $font-size__text; - &.ended { - display: none; - } - &.upcoming { - display: block; - background: white; - } - &.live { - display: block; - background: $color__green; - } + .statusindicator { + width: $spacing__s; + height: $spacing__s; + border-radius: 50%; + + &.ended { + display: none; + } + &.upcoming { + display: block; + background: white; + } + &.live { + display: block; + background: $color__green; } + } - p { margin: 0; } -} \ No newline at end of file + p { + margin: 0; + } +} diff --git a/src/lib/ContestStatus/ContestStatus.types.ts b/src/lib/ContestStatus/ContestStatus.types.ts index 628266b7..8f63e08e 100644 --- a/src/lib/ContestStatus/ContestStatus.types.ts +++ b/src/lib/ContestStatus/ContestStatus.types.ts @@ -7,6 +7,8 @@ export enum Status { export interface ContestStatusProps { /** Status indicator for the current contest. */ status?: Status; + /** Audit status. */ + auditStatus?: AuditStatus | null; /** String of custom classes to extend the default styling of the component. */ className?: string; /** HTML element identifier */ @@ -32,3 +34,32 @@ export const AuditStatus = { } as const; // Take the AuditStatus object, and make a string literal type of the values export type AuditStatus = (typeof AuditStatus)[keyof typeof AuditStatus]; + +export enum AuditPublicStage { + Active = "Active", + Upcoming = "Upcoming", + SubsClosed = "Submissions closed", + Completed = "Completed", +} + +// Grouping mapping of the audit statuses to the public stages +export const MapAuditStatusToAuditPublicStage: Record< + AuditStatus, + AuditPublicStage | null +> = { + [AuditStatus.PreAudit]: AuditPublicStage.Upcoming, + [AuditStatus.Active]: AuditPublicStage.Active, + [AuditStatus.Awarding]: AuditPublicStage.SubsClosed, + [AuditStatus.Judging]: AuditPublicStage.SubsClosed, + [AuditStatus.PJQA]: AuditPublicStage.SubsClosed, + [AuditStatus.Reporting]: AuditPublicStage.SubsClosed, + [AuditStatus.Review]: AuditPublicStage.SubsClosed, + [AuditStatus.Triage]: AuditPublicStage.SubsClosed, + [AuditStatus.Restricted]: AuditPublicStage.SubsClosed, + [AuditStatus.JudgingComplete]: AuditPublicStage.SubsClosed, + [AuditStatus.Paused]: AuditPublicStage.SubsClosed, + [AuditStatus.Completed]: AuditPublicStage.Completed, + // Excluded statuses: + [AuditStatus.LostDeal]: null, + [AuditStatus.Booking]: null, +}; diff --git a/src/lib/ContestTile/ContestTile.scss b/src/lib/ContestTile/ContestTile.scss index 8a867c40..774566b9 100644 --- a/src/lib/ContestTile/ContestTile.scss +++ b/src/lib/ContestTile/ContestTile.scss @@ -1,825 +1,881 @@ @import "../../styles/variables"; -.c4tilewrapper.tile--light, .c4tilewrapper.compact--light { - .c4contesttile.tile--light, .c4contesttile.compact--light { - /* Main component wrapper. Outter wrapper is only for declaring component +.c4tilewrapper.tile--light, +.c4tilewrapper.compact--light { + .c4contesttile.tile--light, + .c4contesttile.compact--light { + /* Main component wrapper. Outter wrapper is only for declaring component as a container for container query compatibility */ - .container--inner { - background: linear-gradient(180deg,hsla(0,0%,100%,.1),hsla(0,0%,100%,.05)) !important; - border: 1px solid hsla(0,0%,100%,.4) !important; - color: $color__white !important; - - &.compact-content { - .body--contest { - a.logo img, img.logo { - border: 1px solid hsla(0,0%,100%,.4) !important; - } - - header .header--status { - border-bottom: 1px solid hsla(0,0%,100%,.4) !important; - } - } + .container--inner { + background: linear-gradient( + 180deg, + hsla(0, 0%, 100%, 0.1), + hsla(0, 0%, 100%, 0.05) + ) !important; + border: 1px solid hsla(0, 0%, 100%, 0.4) !important; + color: $color__white !important; + + &.compact-content { + .body--contest { + a.logo img, + img.logo { + border: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } + + header .header--status { + border-bottom: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } + } - .body--bounty { - a.logo img, img.logo { - border: 1px solid hsla(0,0%,100%,.4) !important; - } + .body--bounty { + a.logo img, + img.logo { + border: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } - header { - border-bottom: 1px solid hsla(0,0%,100%,.4) !important; - } - } + header { + border-bottom: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } + } + } + + &.default-content { + .body--bounty { + header { + a.logo img, + img.logo { + border: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } + } + + .bounty-award { + border-bottom: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } + + @include containerQuery("s") { + .bounty-award { + border-bottom: 0px !important; + } + } + } + + .body--contest { + header { + a.logo img, + img.logo { + border: 1px solid hsla(0, 0%, 100%, 0.4) !important; } + } - &.default-content { - .body--bounty { - header { - a.logo img, img.logo { - border: 1px solid hsla(0,0%,100%,.4) !important; - } - } + .amount { + border-bottom: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } - .bounty-award { - border-bottom: 1px solid hsla(0,0%,100%,.4) !important; - } + @include containerQuery("s") { + .amount { + border-bottom: none !important; + } + } + } - @include containerQuery("s") { - .bounty-award { - border-bottom: 0px !important; - } - } + .footer--bounty { + border-top: 1px solid hsla(0, 0%, 100%, 0.4) !important; + + &.live { + .details { + .c4conteststatus { + border-right: none !important; + } + } + .options { + .contest-redirect { + border-top: none !important; + border-left: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } + } + + @include containerQuery("s") { + .options { + .contest-redirect { + border-left: 1px solid hsla(0, 0%, 100%, 0.4) !important; } + } + } + } + + .details { + .status { + border-right: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } + } + + .options { + .contest-redirect { + border-top: 1px solid hsla(0, 0%, 100%, 0.4) !important; - .body--contest { - header { - a.logo img, img.logo { - border: 1px solid hsla(0,0%,100%,.4) !important; - } + &:hover, + &:focus { + background: hsla(0, 0%, 100%, 0.1); + } - } + &:focus { + border: 1px solid $color__white !important; + } + } - .amount { - border-bottom: 1px solid hsla(0,0%,100%,.4) !important; - } + .c4contesttile--dropdown { + border-left: 1px solid hsla(0, 0%, 100%, 0.4) !important; + border-top: 1px solid hsla(0, 0%, 100%, 0.4) !important; + + &--trigger { + &:hover, + &:focus { + background: hsla(0, 0%, 100%, 0.1) !important; + } + + &:focus { + border: 1px solid $color__white !important; + } + } + } + } - @include containerQuery("s") { - .amount { - border-bottom: none !important; - } - } + @include containerQuery("s") { + &.live { + .options { + .contest-redirect { + border-left: 1px solid hsla(0, 0%, 100%, 0.4) !important; } + } + } + + .details { + .timer { + border-right: 1px solid hsla(0, 0%, 100%, 0.4) !important; + } + } + + .options { + .contest-redirect { + border-top: 0px !important; + } + + .c4contesttile--dropdown { + border-top: 0px !important; + } + } + } + } + + .footer--contest { + border-top: 1px solid hsla(0, 0%, 100%, 0.4) !important; + + .details { + display: flex; + align-items: center; + gap: 0.5rem; + flex: 1 0 0; + padding-left: 0.5rem; + + .audit-tile__status__icon { + width: 1.1rem; + height: 1.1rem; + border-radius: 12.5rem; + + svg { + width: 100%; + height: 100%; + } + } + + .audit-tile__status__status { + flex: 1 0 0; + color: #fff; + } + } + + .options { + .contest-redirect { + border-top: 1px solid hsla(0, 0%, 100%, 0.4) !important; + color: $color__white; + + &:hover, + &:focus { + background: hsla(0, 0%, 100%, 0.1) !important; + } - .footer--bounty { - border-top: 1px solid hsla(0,0%,100%,.4) !important; - - &.live { - .details { - .c4conteststatus { - border-right: none !important; - } - } - .options { - .contest-redirect { - border-top: none !important; - border-left: 1px solid hsla(0,0%,100%,.4) !important; - } - } - - @include containerQuery("s") { - .options { - .contest-redirect { - border-left: 1px solid hsla(0,0%,100%,.4) !important; - } - } - } - } - - .details { - .status { - border-right: 1px solid hsla(0,0%,100%,.4) !important; - } - } - - .options { - .contest-redirect { - border-top: 1px solid hsla(0,0%,100%,.4) !important; - - &:hover, &:focus { - background: hsla(0,0%,100%,.1); - } - - &:focus { - border: 1px solid $color__white !important; - } - } - - .c4contesttile--dropdown { - border-left: 1px solid hsla(0,0%,100%,.4) !important; - border-top: 1px solid hsla(0,0%,100%,.4) !important; - - &--trigger { - &:hover, &:focus { - background: hsla(0,0%,100%,.1) !important; - } - - &:focus { - border: 1px solid $color__white !important; - } - } - } - } - - @include containerQuery("s") { - &.live { - .options { - .contest-redirect { - border-left: 1px solid hsla(0,0%,100%,.4) !important; - } - } - } - - .details { - .timer { - border-right: 1px solid hsla(0,0%,100%,.4) !important; - } - } - - .options { - .contest-redirect { - border-top: 0px !important; - } - - .c4contesttile--dropdown { - border-top: 0px !important; - } - } - } + &:focus { + border: 1px solid white !important; + } + } + + .c4contesttile--dropdown { + border-top: 1px solid hsla(0, 0%, 100%, 0.4) !important; + border-left: 1px solid hsla(0, 0%, 100%, 0.4) !important; + + &--trigger { + &:hover, + &:focus { + background: hsla(0, 0%, 100%, 0.1) !important; } - .footer--contest { - border-top: 1px solid hsla(0,0%,100%,.4) !important; - - .details { - .status:not(.ended) { - border-right: 1px solid hsla(0,0%,100%,.4) !important; - } - - } - - .options { - .contest-redirect { - border-top: 1px solid hsla(0,0%,100%,.4) !important; - color: $color__white; - - &:hover, &:focus { - background: hsla(0,0%,100%,.1) !important; - } - - &:focus { - border: 1px solid white !important; - } - } - - .c4contesttile--dropdown { - border-top: 1px solid hsla(0,0%,100%,.4) !important; - border-left: 1px solid hsla(0,0%,100%,.4) !important; - - &--trigger { - &:hover, &:focus { - background: hsla(0,0%,100%,.1) !important; - } - - &:focus { - border: 1px solid $color__white !important; - } - } - } - } - - &.ended { - .details { - .status.ended { - border-right: 1px solid hsla(0,0%,100%,.4) !important; - } - } - - .options { - .contest-redirect { - border-top: none !important; - width: fit-content; - white-space: nowrap; - } - } - } - - @include containerQuery("s") { - .details { - .timer { - border-right: 1px solid hsla(0,0%,100%,.4) !important; - } - } - - .options { - .contest-redirect { - border-top: none !important; - width: fit-content; - white-space: nowrap; - } - - .c4contesttile--dropdown { - border-top: none !important; - } - } - - } + &:focus { + border: 1px solid $color__white !important; } + } + } + } + + &.ended { + .options { + .contest-redirect { + border-top: none !important; + width: fit-content; + white-space: nowrap; + } + } + } + + @include containerQuery("s") { + .options { + .contest-redirect { + border-top: none !important; + width: fit-content; + white-space: nowrap; + } + + .c4contesttile--dropdown { + border-top: none !important; + } } + } } + } } + } } .c4tilewrapper { + width: 100%; + max-width: 1036px; + position: relative; + container-type: inline-size; + margin-bottom: 1.5rem; + + // Important for stacking context created by container-type css property. + // This makes sure the dropdown always appears above any proceding elements in a list. + &:hover { + z-index: 1; + } + + .c4contesttile, + .c4contesttile.compact, + .c4contesttile.tile--dark, + .c4contesttile.compact--dark { width: 100%; + height: 100%; max-width: 1036px; - position: relative; - container-type: inline-size; - margin-bottom: 1.5rem; - - // Important for stacking context created by container-type css property. - // This makes sure the dropdown always appears above any proceding elements in a list. - &:hover { - z-index: 1; - } - - .c4contesttile, .c4contesttile.compact, .c4contesttile.tile--dark, .c4contesttile.compact--dark { - width: 100%; - height: 100%; - max-width: 1036px; - /* Main component wrapper. Outter wrapper is only for declaring component + /* Main component wrapper. Outter wrapper is only for declaring component as a container for container query compatibility */ - .container--inner { - height: 100%; - background: $color__n-85; - border: 1px solid $color__n-60; - border-radius: $border-radius__base; - color: $color__text; - - a, button { - &:focus { - outline: none; - border: 1px solid $color__white !important; - border-radius: $border-radius__base; - } + .container--inner { + height: 100%; + background: $color__n-85; + border: 1px solid $color__n-60; + border-radius: $border-radius__base; + color: $color__text; + + a, + button { + &:focus { + outline: none; + border: 1px solid $color__white !important; + border-radius: $border-radius__base; + } + } + + &.compact-content { + .body--contest, + .body--bounty { + // Sponsor Image + a.logo img, + img.logo { + border: 1px solid #3e3b4e; + } + + a.logo { + max-width: 26px; + max-height: 26px; + border-radius: 50%; + width: fit-content; + margin: 0; + + img { + border-radius: 50%; + min-width: 1.5rem; + min-height: 1.5rem; + max-width: 1.5rem; + max-height: 1.5rem; + } + } + + img.logo { + min-width: 1.5rem; + min-height: 1.5rem; + max-width: 1.5rem; + max-height: 1.5rem; + border-radius: 50%; + width: fit-content; + margin: 0; + } + } + + .body--bounty { + display: flex; + flex-direction: column; + gap: 0; + + header { + display: flex; + flex-direction: row; + padding: $spacing__base; + gap: $spacing__s; + align-items: center; + border-bottom: 1px solid $color__n-60; + + .title { + text-align: left; + white-space: wrap; + margin: 0; + line-height: 154%; + font-size: $font-size__small; + font-weight: bold; + color: $color__white; } - &.compact-content { - .body--contest, .body--bounty { - // Sponsor Image - a.logo img, img.logo { - border: 1px solid #3e3b4e; - } - - a.logo { - max-width: 26px; - max-height: 26px; - border-radius: 50%; - width: fit-content; - margin: 0; - - img { - border-radius: 50%; - min-width: 1.5rem; - min-height: 1.5rem; - max-width: 1.5rem; - max-height: 1.5rem; - } - } - - img.logo { - min-width: 1.5rem; - min-height: 1.5rem; - max-width: 1.5rem; - max-height: 1.5rem; - border-radius: 50%; - width: fit-content; - margin: 0; - } - } + .type { + margin: 0; + padding: 0; + min-width: auto; + margin-left: auto; + overflow: hidden; + font-size: $font-size__small; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 500; + } + } - .body--bounty { - display: flex; - flex-direction: column; - gap: 0; - - header { - display: flex; - flex-direction: row; - padding: $spacing__base; - gap: $spacing__s; - align-items: center; - border-bottom: 1px solid $color__n-60; - - .title { - text-align: left; - white-space: wrap; - margin: 0; - line-height: 154%; - font-size: $font-size__small; - font-weight: bold; - color: $color__white; - } - - .type { - margin: 0; - padding: 0; - min-width: auto; - margin-left: auto; - overflow: hidden; - font-size: $font-size__small; - text-overflow: ellipsis; - white-space: nowrap; - font-weight: 500; - } - - } - - .content--wrapper { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - strong { - font-size: $font-size__small; - font-weight: bold; - } - - .amount { - margin-top: 0; - text-align: left; - min-width: min-content; - color: $color__white; - font-size: $font-size__small; - font-weight: 500; - } - } - } + .content--wrapper { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; - .body--contest { - padding-top: $spacing__s; - display: flex; - flex-direction: column; - gap: 0; - - header { - .header--status { - display: flex; - justify-content: space-between; - column-gap: 1.5rem; - row-gap: 0.5rem; - border-bottom: 1px solid $color__n-60; - padding: 0rem $spacing__base $spacing__base; - color: $color__white; - font-weight: 500; - font-size: $font-size__small; - - > span { - display: flex; - flex-direction: row; - width: auto; - gap: 0.5rem; - } - - > p, span > * { - margin: 0; - padding: 0 !important; - border: none !important; - - // Removes status label (Live, Soon) - &.status:not(.ended) p { - display: none; - } - - &.type { - flex-grow: 0; // Prevent the type element from growing - flex-shrink: 0; // Prevent the type element from shrinking - white-space: nowrap; // Prevent text from wrapping - } - } - } - } - } + strong { + font-size: $font-size__small; + font-weight: bold; + } - .content--wrapper { - display: flex; - flex-direction: row; - padding: $spacing__base; - gap: $spacing__s; - align-items: center; - - .content { - overflow: hidden; - - .title { - text-align: left; - white-space: wrap; - margin: 0; - line-height: 154%; - font-size: $font-size__small; - font-weight: bold; - color: $color__white; - } - } - } + .amount { + margin-top: 0; + text-align: left; + min-width: min-content; + color: $color__white; + font-size: $font-size__small; + font-weight: 500; + } + } + } - .tags { - padding: 0.25rem 0.5rem 0.5rem; - display: flex; - flex-direction: row; - gap: 0.5rem; - flex-wrap: wrap; - - .c4tag { - height: 1.75rem; - - img { - width: 0.75rem !important; - height: 0.75rem !important; - } - - .icon { - svg { - min-width: 1.125rem; - min-height: 1.125rem; - width: 1.125rem; - height: 1.125rem; - } - } - - - .separator { - height: 26px; - } - - p { - font-size: 0.75rem !important; - } - } + .body--contest { + padding-top: $spacing__s; + display: flex; + flex-direction: column; + gap: 0; + + header { + .header--status { + display: flex; + justify-content: space-between; + column-gap: 1.5rem; + row-gap: 0.5rem; + border-bottom: 1px solid $color__n-60; + padding: 0rem $spacing__base $spacing__base; + color: $color__white; + font-weight: 500; + font-size: $font-size__small; + + > span { + display: flex; + flex-direction: row; + width: auto; + gap: 0.5rem; + } + + > p, + span > * { + margin: 0; + padding: 0 !important; + border: none !important; + + // Removes status label (Live, Soon) + &.status:not(.ended) p { + display: none; } - .amount { - margin: 0px; - margin-left: auto; - min-width: min-content; - color: $color__white; - font-size: $font-size__small; - font-weight: 500; - text-align: right; + &.type { + flex-grow: 0; // Prevent the type element from growing + flex-shrink: 0; // Prevent the type element from shrinking + white-space: nowrap; // Prevent text from wrapping } + } + } + } + } + + .content--wrapper { + display: flex; + flex-direction: row; + padding: $spacing__base; + gap: $spacing__s; + align-items: center; + + .content { + overflow: hidden; + + .title { + text-align: left; + white-space: wrap; + margin: 0; + line-height: 154%; + font-size: $font-size__small; + font-weight: bold; + color: $color__white; + } + } + } + + .tags { + padding: 0.25rem 0.5rem 0.5rem; + display: flex; + flex-direction: row; + gap: 0.5rem; + flex-wrap: wrap; + + .c4tag { + height: 1.75rem; + + img { + width: 0.75rem !important; + height: 0.75rem !important; + } + + .icon { + svg { + min-width: 1.125rem; + min-height: 1.125rem; + width: 1.125rem; + height: 1.125rem; + } + } + + .separator { + height: 26px; + } + + p { + font-size: 0.75rem !important; + } + } + } + + .amount { + margin: 0px; + margin-left: auto; + min-width: min-content; + color: $color__white; + font-size: $font-size__small; + font-weight: 500; + text-align: right; + } + } + + &.default-content { + display: flex; + flex-direction: column; + + .body--bounty { + header .content--wrapper .description { + margin-top: 0 !important; + } + } + + .body--contest, + .body--bounty { + padding-top: $spacing__s; + display: flex; + flex-direction: column-reverse; + gap: 0; + + header { + display: flex; + flex-direction: column; + padding: $spacing__m; + gap: $spacing__m; + + a.logo img, + img.logo { + border: 1px solid #3e3b4e; + } + + a.logo { + max-width: 65px; + max-height: 65px; + border-radius: 50%; + margin: auto; + + img { + object-fit: cover; + border: 1px solid $color__n-60; + border-radius: 50%; + min-width: 63px; + min-height: 63px; + max-width: 63px; + max-height: 63px; + } } + img.logo { + object-fit: cover; + border-radius: 50%; + border: 1px solid $color__n-60; + min-width: 63px; + min-height: 63px; + max-width: 63px; + max-height: 63px; + margin: auto; + } + + .content--wrapper { + .period, + .description { + display: block; + text-align: center; + } - &.default-content { + .tags { + margin-top: 0.5rem; display: flex; - flex-direction: column; + flex-direction: row; + gap: 0.5rem; + flex-wrap: wrap; + justify-content: center; + } + + .title { + margin: 0rem; + color: $color__white; + text-align: center; + font-size: $headline-font-size__xxs; + } + + .description { + margin: $spacing__s 0rem 0rem; + } + } + } - .body--bounty { - header .content--wrapper .description { - margin-top: 0 !important; - } + .bounty-award { + border-bottom: 1px solid $color__n-60; + padding: 0rem $spacing__m $spacing__s; + + .amount { + border-bottom: none; + padding: 0; + } + + p:last-of-type { + margin: 0; + text-align: right; + } + } + + .amount { + margin: 0rem; + min-width: max-content; + border-bottom: 1px solid $color__n-60; + padding: 0rem $spacing__m $spacing__s; + text-align: right; + color: $color__white; + font-weight: 500; + font-size: $font-size__copy; + } + + @include containerQuery("xxs") { + header { + flex-direction: row; + + a.logo, + img.logo { + margin: unset; + } + + a.logo { + max-width: 90px; + max-height: 90px; + + img { + min-width: 88px; + min-height: 88px; + max-width: 88px; + max-height: 88px; + } + } + img.logo { + min-width: 88px; + min-height: 88px; + max-width: 88px; + max-height: 88px; + } + + .content--wrapper { + .period, + .description, + .title { + text-align: left; } - .body--contest, .body--bounty { - padding-top: $spacing__s; - display: flex; - flex-direction: column-reverse; - gap: 0; - - header { - display: flex; - flex-direction: column; - padding: $spacing__m; - gap: $spacing__m; - - a.logo img, img.logo { - border: 1px solid #3e3b4e; - } - - a.logo { - max-width: 65px; - max-height: 65px; - border-radius: 50%; - margin: auto; - - img { - object-fit: cover; - border: 1px solid $color__n-60; - border-radius: 50%; - min-width: 63px; - min-height: 63px; - max-width: 63px; - max-height: 63px; - } - } - img.logo { - object-fit: cover; - border-radius: 50%; - border: 1px solid $color__n-60; - min-width: 63px; - min-height: 63px; - max-width: 63px; - max-height: 63px; - margin: auto; - } - - .content--wrapper { - .period, .description { - display: block; - text-align: center; - } - - .tags { - margin-top: 0.5rem; - display: flex; - flex-direction: row; - gap: 0.5rem; - flex-wrap: wrap; - justify-content: center; - } - - .title { - margin: 0rem; - color: $color__white; - text-align: center; - font-size: $headline-font-size__xxs; - } - - .description { - margin: $spacing__s 0rem 0rem; - } - } - } - - .bounty-award { - border-bottom: 1px solid $color__n-60; - padding: 0rem $spacing__m $spacing__s; - - .amount { - border-bottom: none; - padding: 0; - } - - p:last-of-type { - margin: 0; - text-align: right; - } - } - - .amount { - margin: 0rem; - min-width: max-content; - border-bottom: 1px solid $color__n-60; - padding: 0rem $spacing__m $spacing__s; - text-align: right; - color: $color__white; - font-weight: 500; - font-size: $font-size__copy; - } - - @include containerQuery("xxs") { - header { - flex-direction: row; - - a.logo, img.logo { - margin: unset; - } - - a.logo { - max-width: 90px; - max-height: 90px; - - img { - min-width: 88px; - min-height: 88px; - max-width: 88px; - max-height: 88px; - } - } - img.logo { - min-width: 88px; - min-height: 88px; - max-width: 88px; - max-height: 88px; - } - - .content--wrapper { - .period, .description, .title { - text-align: left; - } - - .tags { - justify-content: flex-start; - } - } - } - } - - @include containerQuery("s") { - padding: $spacing__m; - flex-direction: row; - gap: $spacing__xl; - justify-content: space-between; - - header { - padding: 0rem; - - .title { - font-size: $headline-font-size__s; - } - } - - .bounty-award { - border-bottom: none; - } - .amount { - border-bottom: none; - padding: 0rem; - } - } + .tags { + justify-content: flex-start; } + } + } + } + + @include containerQuery("s") { + padding: $spacing__m; + flex-direction: row; + gap: $spacing__xl; + justify-content: space-between; + + header { + padding: 0rem; + + .title { + font-size: $headline-font-size__s; + } + } + + .bounty-award { + border-bottom: none; + } + .amount { + border-bottom: none; + padding: 0rem; + } + } + } - .footer--contest { - margin-top: auto; + .footer--contest { + margin-top: auto; + + .details { + display: flex; + align-items: center; + gap: 0.5rem; + flex: 1 0 0; + padding-left: 0.5rem; + + .audit-tile__status__icon { + width: 1.1rem; + height: 1.1rem; + border-radius: 12.5rem; + + svg { + width: 100%; + height: 100%; + } + } + + .audit-tile__status__status { + flex: 1 0 0; + color: #fff; + } + } + } + + .footer--bounty { + &.live { + flex-wrap: nowrap; + + .options { + width: fit-content; + + .contest-redirect { + border-top: none; + border-left: 1px solid $color__n-60; + width: max-content; + } + } + + @include containerQuery("s") { + .options { + .contest-redirect { + border-left: 1px solid $color__n-60; } - - .footer--bounty { - &.live { - flex-wrap: nowrap; - - .options { - width: fit-content; - - .contest-redirect { - border-top: none; - border-left: 1px solid $color__n-60; - width: max-content; - } - } - - @include containerQuery("s") { - .options { - .contest-redirect { - border-left: 1px solid $color__n-60; - } - } - } - } + } + } + } + } + + .footer--contest, + .footer--bounty { + border-top: 1px solid $color__n-60; + display: flex; + flex-wrap: wrap; + flex-direction: row; + height: fit-content; + + .details { + display: flex; + flex-direction: row; + width: 100%; + + .status, + .timer { + padding: $spacing__s $spacing__m; + } + + .status { + justify-content: flex-start; + width: max-content; + border-right: 1px solid $color__n-60; + + &.ended, + &.bounty { + border-right: 0px; + } + } + + .timer { + width: 100%; + margin: 0px; + } + } + + .options { + display: flex; + flex-direction: row; + width: 100%; + + .contest-redirect { + padding: $spacing__s $spacing__m; + text-align: center; + width: 100%; + border-top: 1px solid $color__n-60; + text-decoration: none; + color: $color__white; + + &:hover, + &:focus { + background: $color__n-80; + } + + &:focus { + border-color: unset !important; + border-radius: 0px; + } + } + + .c4contesttile--dropdown { + border-left: 1px solid $color__n-60; + border-top: 1px solid $color__n-60; + border-radius: 0px; + + &--trigger { + height: 100%; + padding: 0rem $spacing__m; + background: none; + border: none; + color: $color__white; + cursor: pointer; + + svg { + min-width: 2rem; + min-height: 2rem; + width: 2rem; + height: 2rem; } - .footer--contest, .footer--bounty { - border-top: 1px solid $color__n-60; - display: flex; - flex-wrap: wrap; - flex-direction: row; - height: fit-content; - - .details { - display: flex; - flex-direction: row; - width: 100%; - - .status, .timer { - padding: $spacing__s $spacing__m; - } - - .status { - justify-content: flex-start; - width: max-content; - border-right: 1px solid $color__n-60; - - &.ended, &.bounty { - border-right: 0px; - } - } - - .timer { - width: 100%; - margin: 0px; - } - } - - .options { - display: flex; - flex-direction: row; - width: 100%; - - .contest-redirect { - padding: $spacing__s $spacing__m; - text-align: center; - width: 100%; - border-top: 1px solid $color__n-60; - text-decoration: none; - color: $color__white; - - &:hover, &:focus { - background: $color__n-80; - } - - &:focus { - border-color: unset !important; - border-radius: 0px; - } - } - - .c4contesttile--dropdown { - border-left: 1px solid $color__n-60; - border-top: 1px solid $color__n-60; - border-radius: 0px; - - - &--trigger { - height: 100%; - padding: 0rem $spacing__m; - background: none; - border: none; - color: $color__white; - cursor: pointer; - - svg { - min-width: 2rem; - min-height: 2rem; - width: 2rem; - height: 2rem; - } - - &:hover { - background: $color__n-80; - } - } - } - } - - &.ended { - flex-wrap: nowrap; - - .details { - .status.ended, .status.bounty { - width: 100%; - border-right: 1px solid $color__n-60; - } - } - - .options { - width: fit-content; - - .contest-redirect { - width: fit-content; - white-space: nowrap; - border-top: none; - } - - .c4contesttile--dropdown { - border-top: none; - } - } - } - - @include containerQuery("s") { - flex-wrap: nowrap; - - .details { - .timer { - border-right: 1px solid $color__n-60; - } - } - - .options { - width: fit-content; - - .contest-redirect { - width: fit-content; - white-space: nowrap; - border-top: none; - } - - .c4contesttile--dropdown { - border-top: none; - } - } - } + &:hover { + background: $color__n-80; } + } + } + } + + &.ended { + flex-wrap: nowrap; + + .details { + .status.ended, + .status.bounty { + width: 100%; + border-right: 1px solid $color__n-60; + } + } + + .options { + width: fit-content; + + .contest-redirect { + width: fit-content; + white-space: nowrap; + border-top: none; + } + + .c4contesttile--dropdown { + border-top: none; + } } + } + + @include containerQuery("s") { + flex-wrap: nowrap; + + .details { + .timer { + border-right: 1px solid $color__n-60; + } + } + + .options { + width: fit-content; + + .contest-redirect { + width: fit-content; + white-space: nowrap; + border-top: none; + } + + .c4contesttile--dropdown { + border-top: none; + } + } + } } + } } + } } // Compact tile overrides .c4contesttile.compact { - .c4conteststatus { - align-items: start; + .c4conteststatus { + align-items: start; - .statusindicator { - margin-top: 8px; - } + .statusindicator { + margin-top: 8px; } -} \ No newline at end of file + } +} diff --git a/src/lib/ContestTile/DefaultTemplate.tsx b/src/lib/ContestTile/DefaultTemplate.tsx index 2d44293f..b76d8440 100644 --- a/src/lib/ContestTile/DefaultTemplate.tsx +++ b/src/lib/ContestTile/DefaultTemplate.tsx @@ -10,6 +10,7 @@ import { isBefore } from "date-fns"; import { Dropdown } from "../Dropdown"; import { Icon } from "../Icon"; import { Tag } from "../Tag"; +import { AuditStatusSection } from "../ContestStatus/AuditStatusSection"; export default function DefaultTemplate({ @@ -250,7 +251,16 @@ function IsContest({ updateContestTileStatus: () => void; contestTimelineObject: ContestSchedule | undefined; }) { - const { contestUrl, amount, findingsRepo, startDate, endDate, ecosystem, languages } = contestData; + const { + contestUrl, + amount, + findingsRepo, + startDate, + endDate, + ecosystem, + languages, + status, + } = contestData; let ecosystemLogoName: string = ""; if (ecosystem) { switch (ecosystem) { @@ -351,22 +361,11 @@ function IsContest({ {/* Contest tile footer */}