Skip to content

Commit

Permalink
tabs, capitalize, socials
Browse files Browse the repository at this point in the history
  • Loading branch information
indaviande committed Dec 4, 2024
1 parent 8d18d1c commit de3f086
Show file tree
Hide file tree
Showing 20 changed files with 274 additions and 107 deletions.
54 changes: 36 additions & 18 deletions src/components/composite/Hero.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import type { Opportunity } from "@merkl/api";
import { useLocation } from "@remix-run/react";
import { Box, Container, Divider, Group, Icon, type IconProps, Icons, Text, Title } from "dappkit";
import {
Container,
Divider,
Group,
Icon,
type IconProps,
Icons,
Tabs,
Text,
Title,
} from "dappkit";
import { Button } from "dappkit";
import config from "merkl.config";
import type { PropsWithChildren, ReactNode } from "react";
Expand All @@ -12,18 +22,28 @@ export type HeroProps = PropsWithChildren<{
navigation?: { label: ReactNode; link: string };
description: ReactNode;
tags?: ReactNode[];
tabs?: { label: ReactNode; link: string }[];
tabs?: { label: ReactNode; link: string; key: string }[];
opportunity?: Opportunity;
}>;

export default function Hero({ navigation, breadcrumbs, icons, title, description, tags, tabs, children }: HeroProps) {
export default function Hero({
navigation,
breadcrumbs,
icons,
title,
description,
tags,
tabs,
children,
}: HeroProps) {
const location = useLocation();

return (
<>
<Group
className="flex-row justify-between aspect-[1440/440] bg-cover bg-no-repeat xl:aspect-auto xl:min-h-[400px]"
style={{ backgroundImage: `url('${config.images.hero}')` }}>
style={{ backgroundImage: `url('${config.images.hero}')` }}
>
<Container>
<Group className="flex-col h-full py-xl gap-xl lg:gap-xs">
<Group className="items-center">
Expand All @@ -32,10 +52,15 @@ export default function Hero({ navigation, breadcrumbs, icons, title, descriptio
<Button to={navigation?.link} look="soft" size="xs">
Home
</Button>
{breadcrumbs?.map(breadcrumb => {
{breadcrumbs?.map((breadcrumb) => {
if (breadcrumb.component) return breadcrumb.component;
return (
<Button key={breadcrumb.link} to={breadcrumb.link} look="soft" size="xs">
<Button
key={breadcrumb.link}
to={breadcrumb.link}
look="soft"
size="xs"
>
<Icon remix="RiArrowRightSLine" />
{breadcrumb.name}
</Button>
Expand All @@ -49,14 +74,14 @@ export default function Hero({ navigation, breadcrumbs, icons, title, descriptio
{!!icons && (
<Icons size="lg">
{icons?.length > 1
? icons?.map(icon => (
? icons?.map((icon) => (
<Icon
className="hidden md:block text-main-12 !w-lg*4 !h-lg*4"
key={`${Object.values(icon)}`}
{...icon}
/>
))
: icons?.map(icon => (
: icons?.map((icon) => (
<Icon
className="hidden md:block text-main-12 !w-xl*4 !h-xl*4"
key={`${Object.values(icon)}`}
Expand Down Expand Up @@ -121,16 +146,9 @@ export default function Hero({ navigation, breadcrumbs, icons, title, descriptio
</Group>
<Container>
{!!tabs && (
<Box size="sm" look="base" className="flex-row mt-md w-min">
{tabs?.map(tab => (
<Button
look={location.pathname === tab.link ? "hype" : "base"}
to={tab.link}
key={`${tab.label}-${tab.link}`}>
{tab.label}
</Button>
))}
</Box>
<Group size="xl" className="my-lg">
<Tabs tabs={tabs} look="base" size="lg" />
</Group>
)}
</Container>
<div>{children}</div>
Expand Down
5 changes: 5 additions & 0 deletions src/components/element/Socials.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export default function Socials() {
<Icon remix="RiDiscordFill" />
</Button>
)}
{!!config.socials.medium && (
<Button look="base" size="lg" external to={config.socials.medium}>
<Icon remix="RiMediumFill" />
</Button>
)}
</Group>
);
}
2 changes: 1 addition & 1 deletion src/components/element/Tag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export default function Tag<T extends keyof TagTypes>({ type, value, ...props }:
</Button>
</Group>
}>
<PrimitiveTag look="bold" key={value} {...props}>
<PrimitiveTag look="soft" key={value} {...props}>
<Icon size={props?.size} {...action.icon} />
{action?.label}
</PrimitiveTag>
Expand Down
2 changes: 1 addition & 1 deletion src/components/element/chain/ChainTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createTable } from "dappkit";

export const [ChainTable, ChainRow, chainColumns] = createTable({
chain: {
name: "CHAIN",
name: "Chain",
size: "minmax(350px,1fr)",
compact: "1fr",
className: "justify-start",
Expand Down
2 changes: 1 addition & 1 deletion src/components/element/protocol/ProtocolTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createTable } from "dappkit";

export const [ProtocolTable, ProtocolRow, protocolColumns] = createTable({
protocol: {
name: "PROTOCOL",
name: "Protocol",
size: "minmax(350px,1fr)",
compact: "1fr",
className: "justify-start",
Expand Down
12 changes: 8 additions & 4 deletions src/components/element/rewards/ClaimRewardsChainTable.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { createTable } from "dappkit";

export const [ClaimRewardsChainTable, ClaimRewardsChainRow, claimRewardsChainColumns] = createTable({
export const [
ClaimRewardsChainTable,
ClaimRewardsChainRow,
claimRewardsChainColumns,
] = createTable({
chain: {
name: "CHAIN",
name: "Chain",
size: "minmax(180px,1fr)",
compact: "1fr",
className: "justify-start",
main: true,
},
unclaimed: {
name: "UNCLAIMED",
name: "Unclaimed",
size: "minmax(100px,150px)",
compactSize: "minmax(min-content,1fr)",
className: "justify-end",
},
claimed: {
name: "CLAIMED",
name: "Claimed",
size: "minmax(100px,150px)",
compactSize: "minmax(min-content,1fr)",
className: "justify-end",
Expand Down
83 changes: 60 additions & 23 deletions src/components/element/rewards/ClaimRewardsChainTableRow.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import type { Reward } from "@merkl/api";
import { Button, type Component, Icon, Space, Text, Value, mergeClass } from "dappkit";
import {
Button,
type Component,
Icon,
Space,
Text,
Value,
mergeClass,
} from "dappkit";
import TransactionButton from "packages/dappkit/src/components/dapp/TransactionButton";
import Collapsible from "packages/dappkit/src/components/primitives/Collapsible";
import EventBlocker from "packages/dappkit/src/components/primitives/EventBlocker";
Expand All @@ -23,60 +31,80 @@ export default function ClaimRewardsChainTableRow({
...props
}: ClaimRewardsChainTableRowProps) {
const [open, setOpen] = useState(false);
const [selectedTokens, setSelectedTokens] = useState<Set<string>>(new Set<string>());
const [selectedTokens, setSelectedTokens] = useState<Set<string>>(
new Set<string>()
);

const { address: user, chainId, switchChain } = useWalletContext();
const isUserRewards = useMemo(() => user === from, [user, from]);
const isAbleToClaim = useMemo(
() => isUserRewards && !reward.rewards.every(({ amount, claimed }) => amount === claimed),
[isUserRewards, reward],
() =>
isUserRewards &&
!reward.rewards.every(({ amount, claimed }) => amount === claimed),
[isUserRewards, reward]
);
const isOnCorrectChain = useMemo(
() => reward.chain.id === chainId,
[reward, chainId]
);
const isOnCorrectChain = useMemo(() => reward.chain.id === chainId, [reward, chainId]);

const claimTransaction = useMemo(() => {
const abi = parseAbi(["function claim(address[],address[],uint256[],bytes32[][]) view returns (uint256)"]);
const abi = parseAbi([
"function claim(address[],address[],uint256[],bytes32[][]) view returns (uint256)",
]);

const tokenAddresses = reward.rewards.map(({ token }) => token.address as `0x${string}`);
const tokenAddresses = reward.rewards.map(
({ token }) => token.address as `0x${string}`
);
const accumulatedRewards = reward.rewards.map(({ amount }) => amount);
const proofs = reward.rewards.map(({ proofs }) => proofs as `0x${string}`[]);
const proofs = reward.rewards.map(
({ proofs }) => proofs as `0x${string}`[]
);

if (!reward || !user || !isUserRewards) return;
return {
to: reward.distributor,
data: encodeFunctionData({
abi,
functionName: "claim",
args: [tokenAddresses.map(() => user as `0x${string}`), tokenAddresses, accumulatedRewards, proofs],
args: [
tokenAddresses.map(() => user as `0x${string}`),
tokenAddresses,
accumulatedRewards,
proofs,
],
}),
};
}, [user, reward, isUserRewards]);

const unclaimed = useMemo(() => {
return reward.rewards.reduce(
(sum, { amount, claimed, token: { decimals, price } }) =>
sum + Number.parseFloat(formatUnits(amount - claimed, decimals)) * price,
0,
sum +
Number.parseFloat(formatUnits(amount - claimed, decimals)) * price,
0
);
}, [reward]);

const claimed = useMemo(() => {
return reward.rewards.reduce(
(sum, { claimed, token: { decimals, price } }) => sum + Number.parseFloat(formatUnits(claimed, decimals)) * price,
0,
(sum, { claimed, token: { decimals, price } }) =>
sum + Number.parseFloat(formatUnits(claimed, decimals)) * price,
0
);
}, [reward]);

const renderTokenRewards = useMemo(
() =>
reward.rewards
.sort((a, b) => Number(b.amount - b.claimed - (a.amount - a.claimed)))
.map(_reward => (
.map((_reward) => (
<ClaimRewardsTokenTableRow
className="cursor-pointer [&>*>*]:cursor-auto"
checkedState={[
selectedTokens.has(_reward.token.address),
checked => {
setSelectedTokens(t => {
(checked) => {
setSelectedTokens((t) => {
if (checked) t.add(_reward.token.address);
else t.delete(_reward.token.address);

Expand All @@ -88,14 +116,14 @@ export default function ClaimRewardsChainTableRow({
reward={_reward}
/>
)),
[reward, selectedTokens],
[reward, selectedTokens]
);

return (
<ClaimRewardsChainRow
{...props}
className={mergeClass("cursor-pointer [&>*>*]:cursor-auto", className)}
onClick={() => setOpen(o => !o)}
onClick={() => setOpen((o) => !o)}
chainColumn={
<>
<Tag type="chain" value={reward.chain} />
Expand All @@ -107,11 +135,18 @@ export default function ClaimRewardsChainTableRow({
<EventBlocker>
{isAbleToClaim &&
(isOnCorrectChain ? (
<TransactionButton disabled={!claimTransaction} className="ml-xl" look="hype" tx={claimTransaction}>
<TransactionButton
disabled={!claimTransaction}
className="ml-xl"
look="hype"
tx={claimTransaction}
>
Claim
</TransactionButton>
) : (
<Button onClick={() => switchChain(reward.chain.id)}>Switch</Button>
<Button onClick={() => switchChain(reward.chain.id)}>
Switch
</Button>
))}
</EventBlocker>
</>
Expand All @@ -125,17 +160,19 @@ export default function ClaimRewardsChainTableRow({
<Value size="lg" format="$0,0">
{claimed}
</Value>
}>
}
>
<Collapsible state={[open, setOpen]}>
<Space size="md" />
<ClaimRewardsTokenTable
tokenHeader={
<Text size="xs" className="pl-md">
TOKEN
Token
</Text>
}
size="sm"
look="soft">
look="soft"
>
{renderTokenRewards}
</ClaimRewardsTokenTable>
</Collapsible>
Expand Down
8 changes: 4 additions & 4 deletions src/components/element/rewards/ClaimRewardsTokenTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@ import { createTable } from "dappkit";

export const [ClaimRewardsTokenTable, ClaimRewardsTokenRow, claimRewardsTokenColumns] = createTable({
token: {
name: "TOKEN",
name: "Token",
size: "minmax(100px,1fr)",
compact: "1fr",
className: "justify-start",
main: true,
},
pending: {
name: "PENDING",
name: "Pending",
size: "minmax(min-content,150px)",
compactSize: "minmax(min-content,200px)",
className: "justify-end",
},
amount: {
name: "UNCLAIMED",
name: "Unclaimed",
size: "minmax(min-content,150px)",
compactSize: "minmax(min-content,200px)",
className: "justify-end",
},
claimed: {
name: "CLAIMED",
name: "Claimed",
size: "minmax(min-content,150px)",
compactSize: "minmax(min-content,200px)",
className: "justify-end",
Expand Down
Loading

0 comments on commit de3f086

Please sign in to comment.