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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@code4rena/components-library",
"version": "3.0.2",
"version": "3.1.0",
"description": "Code4rena's official components library ",
"types": "./dist/lib.d.ts",
"exports": {
Expand Down
69 changes: 64 additions & 5 deletions src/lib/ContestTile/CompactTemplate.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React, { useCallback, useEffect, useState } from 'react';
import clsx from "clsx";
import { BountyTileData, ContestSchedule, ContestTileData, ContestTileProps, ContestTileVariant } from "./ContestTile.types";
import { Status } from '../types';
import { Status, TagSize, TagVariant } from '../types';
import { ContestStatus } from '../ContestStatus';
import { Countdown } from './ContestTile';
import { getDates } from '../../utils/time';
import { Tag } from '../Tag';
import { Icon } from '../Icon';
import wolfbotIcon from "../../../public/icons/wolfbot.svg";

export default function CompactTemplate({
variant,
Expand All @@ -19,6 +22,7 @@ export default function CompactTemplate({
"compact--light": variant === ContestTileVariant.COMPACT_LIGHT,
"compact--dark": variant === ContestTileVariant.COMPACT_DARK,
});
const isDarkTile = variant === ContestTileVariant.DARK || variant === ContestTileVariant.COMPACT_DARK;

const tileClasses = clsx({
c4contesttile: true,
Expand All @@ -29,11 +33,13 @@ export default function CompactTemplate({
<div id={htmlId ?? undefined} className={clsx(variantClasses, tileClasses)}>
<div className="container--inner compact-content">
{contestData && <IsContest
isDarkTile={isDarkTile}
title={title}
contestData={contestData}
sponsorUrl={sponsorUrl}
sponsorImage={sponsorImage} />}
{bountyData && <IsBounty
isDarkTile={isDarkTile}
title={title}
bountyData={bountyData}
sponsorUrl={sponsorUrl}
Expand All @@ -45,14 +51,20 @@ export default function CompactTemplate({
}


const IsContest = ({title, contestData, sponsorUrl, sponsorImage}: {
const IsContest = ({title, isDarkTile = true, contestData, sponsorUrl, sponsorImage}: {
title: string;
isDarkTile: boolean;
contestData: ContestTileData;
sponsorUrl: string | undefined;
sponsorImage: string | undefined;
}) => {
const { startDate, endDate, amount, contestUrl, contestType } = contestData;
const { startDate, endDate, amount, contestUrl, contestType, ecosystem, languages } = contestData;
const [contestTimelineObject, setContestTimelineObject] = useState<ContestSchedule | undefined>();
const [hasBotRace, setHasBotRace] = useState(contestData ? !!contestData.botFindingsRepo : false);
let ecosystemLogoName: string = "";
if (ecosystem && (ecosystem === "Polkadot" || ecosystem === "Ethereum")) {
ecosystemLogoName = `logo-${ecosystem.toLowerCase()}`
}

const updateContestTileStatus = useCallback(() => {
if (contestData) {
Expand Down Expand Up @@ -137,16 +149,48 @@ const IsContest = ({title, contestData, sponsorUrl, sponsorImage}: {
</div>
<p className="amount">{amount}</p>
</div>
{((hasBotRace && contestTimelineObject && (contestTimelineObject.botRaceStatus === Status.UPCOMING ||
contestTimelineObject.botRaceStatus === Status.LIVE)) || ecosystem || languages?.length > 0) && <div className="tags">
{hasBotRace && contestTimelineObject &&
(contestTimelineObject.botRaceStatus === Status.UPCOMING ||
contestTimelineObject.botRaceStatus === Status.LIVE) && (
<Tag
variant={isDarkTile ? TagVariant.DEFAULT : TagVariant.WHITE_OUTLINE}
label={contestTimelineObject.botRaceStatus === Status.LIVE ? "Bot Race live" : "1st hour: Bot Race"}
iconLeft={wolfbotIcon}
size={TagSize.NARROW}
/>
)}
{ecosystem && <Tag
variant={isDarkTile ? TagVariant.DEFAULT : TagVariant.WHITE_OUTLINE}
label={ecosystem}
iconLeft={ecosystemLogoName ? <Icon name={ecosystemLogoName} size="small" color="white" /> : undefined}
size={TagSize.NARROW}
/>}
{languages
&& languages.length > 0
&& languages.map((language) => <Tag
variant={isDarkTile ? TagVariant.DEFAULT : TagVariant.WHITE_OUTLINE}
label={language}
size={TagSize.NARROW}
/>
)}
</div>}
</div>
)}

const IsBounty = ({title, bountyData, sponsorUrl, sponsorImage}: {
const IsBounty = ({title, isDarkTile = true, bountyData, sponsorUrl, sponsorImage}: {
title: string;
isDarkTile: boolean;
bountyData: BountyTileData;
sponsorUrl: string | undefined;
sponsorImage: string | undefined;
}) => {
const { amount, bountyUrl } = bountyData;
const { amount, bountyUrl, ecosystem, languages } = bountyData;
let ecosystemLogoName: string = "";
if (ecosystem && (ecosystem === "Polkadot" || ecosystem === "Ethereum")) {
ecosystemLogoName = `logo-${ecosystem.toLowerCase()}`
}

return (
<div className="body--bounty">
Expand Down Expand Up @@ -189,5 +233,20 @@ const IsBounty = ({title, bountyData, sponsorUrl, sponsorImage}: {
<strong>Max Bounty</strong>
<p className="amount">{amount}</p>
</div>
{(ecosystem || languages?.length > 0) && <div className="tags">
{ecosystem && <Tag
variant={isDarkTile ? TagVariant.DEFAULT : TagVariant.WHITE_OUTLINE}
label={ecosystem}
iconLeft={ecosystemLogoName ? <Icon name={ecosystemLogoName} size="small" color="white" /> : undefined}
size={TagSize.NARROW}
/>}
{languages
&& languages.length > 0
&& languages.map((language) => <Tag
variant={isDarkTile ? TagVariant.DEFAULT : TagVariant.WHITE_OUTLINE}
label={language}
size={TagSize.NARROW} />
)}
</div>}
</div>
)}
56 changes: 44 additions & 12 deletions src/lib/ContestTile/ContestTile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,39 @@
}
}

.tags {
padding: 0.24rem 0.5rem 0.5rem;
display: flex;
flex-direction: row;
gap: 0.5rem;
flex-wrap: wrap;

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 {
padding-top: 5px;
padding-bottom: 5px;
font-size: 0.75rem !important;
}
}

.amount {
margin: 0px;
margin-left: auto;
Expand Down Expand Up @@ -506,24 +539,23 @@
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;
}

.bot-race-status {
display: flex;
gap: 0.5rem;
margin-top: 0.25rem;
align-items: center;
justify-content: center;
color: $color__white;
font-weight: 700;
}

.description {
margin: $spacing__s 0rem 0rem;
}
Expand Down Expand Up @@ -587,7 +619,7 @@
text-align: left;
}

.bot-race-status {
.tags {
justify-content: flex-start;
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/lib/ContestTile/ContestTile.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Fragment } from "react";
import { ContestTile } from "./ContestTile";
import { Meta, StoryObj } from "@storybook/react";
import { ContestTileVariant } from "./ContestTile.types";
import { CodingLanguage, ContestEcosystem, ContestTileVariant } from "./ContestTile.types";

const meta: Meta<typeof ContestTile> = {
component: ContestTile,
Expand Down Expand Up @@ -39,9 +39,12 @@ const defaultArgs = {
contestType: "Open Audit",
isUserCertified: false,
contestId: 321,
ecosystem: "Ethereum" as ContestEcosystem,
languages: ["Rust"] as CodingLanguage[],
contestUrl: "https://code4rena.com/audits/2023-07-axelar-network#top",
contestRepo: "https://github.com/code-423n4/2023-07-axelar",
findingsRepo: "https://github.com/code-423n4/2023-07-axelar",
botFindingsRepo: "https://github.com/code-423n4/2023-07-axelar",
amount: "$80,000 USDC",
startDate: "2030-07-12T18:00:00Z",
endDate: "2030-07-21T18:00:00.000Z",
Expand Down Expand Up @@ -162,6 +165,8 @@ BountyTile.args = {
startDate: "2023-07-12T18:00:00Z",
repoUrl: "https://github.com/code-423n4/2023-07-axelar",
bountyUrl: "https://code4rena.com/audits/2023-07-axelar-network#top",
ecosystem: "Polkadot" as ContestEcosystem,
languages: ["Rust"] as CodingLanguage[],
},
variant: ContestTileVariant.LIGHT,
sponsorImage: "/logos/apple-touch-icon.png",
Expand Down
12 changes: 12 additions & 0 deletions src/lib/ContestTile/ContestTile.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export enum ContestTileVariant {
COMPACT_DARK = "COMPACT_DARK"
}

export type ContestEcosystem = "Algorand" | "Aptos" | "Blast" | "Cosmos" | "Ethereum" | "EVM" | "NEAR" | "Polkadot" | "Scroll" | "Sei" | "Solana" | "StarkNet" | "Stellar" | "Sui" | "Other";

export type CodingLanguage = "Cairo" | "GO" | "HUFF" | "Ink" | "Move" | "Noir" | "Other" | "Rain" | "Rust" | "Rust evm" | "Solidity" | "Vyper" | "Yui";

export interface ContestTileProps {
/** An html `id` for the contest tile's wrapping div. */
htmlId?: string;
Expand Down Expand Up @@ -38,6 +42,10 @@ export interface BountyTileData {
bountyUrl: string;
/** Absolute url to the bounty's source code. */
repoUrl: string;
/** Ecosystem being deployed to for the current contest. */
ecosystem: ContestEcosystem;
/** Coding language for the current contest. */
languages: CodingLanguage[];
/** Callback function to be triggered on bounty time/status changes. */
updateBountyStatus?: () => void;
}
Expand All @@ -57,6 +65,10 @@ export interface ContestTileData {
findingsRepo: string;
/** Absolute url to the contest's findings. */
botFindingsRepo?: string;
/** Ecosystem being deployed to for the current contest. */
ecosystem: ContestEcosystem;
/** Coding language for the current contest. */
languages: CodingLanguage[];
/** Reward pool for the current contest. */
amount: string;
/** Callback function to be triggered on contest time/status changes. */
Expand Down
Loading