Compare commits

...
27 changed files with 1190 additions and 68 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 947 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 KiB

@@ -0,0 +1,83 @@
import { Input, InputError } from '@vegaprotocol/ui-toolkit';
import type { FieldValues } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import classNames from 'classnames';
import { useSearchParams } from 'react-router-dom';
import { useEffect } from 'react';
import { Button } from './buttons';
import { useVegaWallet } from '@vegaprotocol/wallet';
export const ApplyCodeForm = () => {
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
const {
register,
handleSubmit,
formState: { errors },
setValue,
setError,
} = useForm();
const [params] = useSearchParams();
useEffect(() => {
const code = params.get('code');
if (code) setValue('code', code);
}, [params, setValue]);
const onSubmit = ({ code }: FieldValues) => {
if (isReadOnly || !pubKey || !code || code.length === 0) {
return;
}
sendTx(pubKey, {
applyReferralCode: {
id: code as string,
},
})
.then((res) => {
// TODO: Do something with response
})
.catch((err) => {
setError('code', {
type: 'required',
message: 'Your code has been rejected',
});
});
};
return (
<div className="mx-auto lg:w-1/2">
<h3 className="mb-5 text-xl text-center uppercase calt">
Apply a referral code
</h3>
<p className="mb-6 text-center">Enter a referral code</p>
<form
className={classNames('w-full flex flex-col gap-3', {
'animate-shake': Boolean(errors.code),
})}
onSubmit={handleSubmit(onSubmit)}
>
<label className="flex-grow">
<span className="block mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
Your referral code
</span>
<Input
hasError={Boolean(errors.code)}
{...register('code', {
required: 'You have to provide a code to apply it.',
})}
/>
</label>
<Button
disabled={isReadOnly || !pubKey}
className="w-full"
type="submit"
>
Apply
</Button>
</form>
{errors.code && (
<InputError>{errors.code.message?.toString()}</InputError>
)}
</div>
);
};
@@ -0,0 +1,83 @@
import { Intent, TradingButton } from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import type { ComponentProps, HTMLAttributes } from 'react';
import { forwardRef } from 'react';
import { NavLink } from 'react-router-dom';
type RainbowButtonProps = {
variant?: 'full' | 'border';
};
export const RainbowButton = ({
variant = 'full',
children,
className,
...props
}: RainbowButtonProps & HTMLAttributes<HTMLButtonElement>) => (
<button
className={classNames(
'bg-rainbow hover:bg-none hover:bg-vega-pink-500 rounded-lg overflow-hidden',
{
'px-5 py-3 text-white': variant === 'full',
'p-[0.125rem]': variant === 'border',
},
className
)}
{...props}
>
<div
className={classNames({
'bg-white dark:bg-vega-cdark-900 text-black dark:text-white px-5 py-3 rounded-[0.35rem] overflow-hidden':
variant === 'border',
})}
>
{children}
</div>
</button>
);
const RAINBOW_TAB_STYLE = classNames(
'inline-block',
'bg-vega-clight-500 dark:bg-vega-cdark-500 hover:bg-vega-clight-400 dark:hover:bg-vega-cdark-400',
'data-[state="active"]:text-white data-[state="active"]:bg-rainbow data-[state="active"]:hover:bg-none data-[state="active"]:hover:bg-vega-pink-500 dark:data-[state="active"]:hover:bg-vega-pink-500',
'[&.active]:text-white [&.active]:bg-rainbow [&.active]:hover:bg-none [&.active]:hover:bg-vega-pink-500 dark:[&.active]:hover:bg-vega-pink-500',
'px-5 py-3',
'first:rounded-tl-lg last:rounded-tr-lg'
);
export const RainbowTabButton = forwardRef<
HTMLButtonElement,
HTMLAttributes<HTMLButtonElement>
>(({ children, ...props }, ref) => (
<button ref={ref} className={RAINBOW_TAB_STYLE} {...props}>
{children}
</button>
));
RainbowTabButton.displayName = 'RainbowTabButton';
export const RainbowTabLink = ({
to,
children,
...props
}: ComponentProps<typeof NavLink>) => (
<NavLink to={to} className={RAINBOW_TAB_STYLE} {...props}>
{children}
</NavLink>
);
export const Button = forwardRef<
HTMLButtonElement,
ComponentProps<typeof TradingButton>
>(({ children, intent, type, ...props }, ref) => {
return (
<TradingButton
ref={ref}
intent={intent || type === 'submit' ? Intent.Primary : Intent.None}
type={type}
{...props}
>
{children}
</TradingButton>
);
});
Button.displayName = 'TradingButton';
@@ -0,0 +1,6 @@
export const BORDER_COLOR = 'border-vega-clight-500 dark:border-vega-cdark-500';
export const GRADIENT =
'bg-gradient-to-b from-vega-clight-800 dark:from-vega-cdark-800 to-transparent';
export const SKY_BACKGROUND =
'bg-[url(/assets/sky-light.png)] dark:bg-[url(/assets/sky-dark.png)] bg-[40%_0px] bg-[length:1440px] bg-no-repeat';
@@ -0,0 +1,61 @@
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { RainbowButton } from './buttons';
import { useState } from 'react';
import classNames from 'classnames';
export const CreateCodeForm = () => {
const [err, setErr] = useState<boolean | null>(null);
const openWalletDialog = useVegaWalletDialogStore(
(store) => store.openVegaWalletDialog
);
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
const onSubmit = () => {
if (isReadOnly || !pubKey) {
setErr(true);
} else {
setErr(false);
sendTx(pubKey, {
createReferralSet: {
isTeam: false,
},
})
.then((res) => {
// TODO: Do something with response
})
.catch((err) => {
// TODO: Do something with rejection
});
}
};
return (
<div className="mx-auto lg:w-1/2">
<h3 className="mb-5 text-xl text-center uppercase calt">
Create a referral code
</h3>
<p className="mb-6 text-center">
Generate a referral code to share with your friends and start earning
commission.
</p>
{pubKey ? (
<div className="text-center">
<RainbowButton
className={classNames({
'animate-shake': err,
})}
variant="border"
onClick={() => onSubmit()}
>
Create a referral code
</RainbowButton>
</div>
) : (
<div className="text-center">
<RainbowButton variant="border" onClick={() => openWalletDialog()}>
Connect wallet
</RainbowButton>
</div>
)}
</div>
);
};
@@ -0,0 +1,46 @@
import { isRouteErrorResponse, useNavigate, useRouteError } from 'react-router';
import { RainbowButton } from './buttons';
import { AnimatedDudeWithWire } from './graphics/dude';
import { LayoutWithSky } from './layout';
export const ErrorBoundary = () => {
const error = useRouteError();
const navigate = useNavigate();
const title = isRouteErrorResponse(error)
? `${error.status} ${error.statusText}`
: 'Something went wrong';
const code = isRouteErrorResponse(error) ? error.status : 0;
const messages: Record<number, string> = {
0: 'An unknown error occurred.',
404: "The page you're looking for doesn't exists.",
};
return (
<LayoutWithSky className="pt-32">
<div
aria-hidden
className="absolute top-64 right-[220px] md:right-[340px] max-sm:hidden"
>
<AnimatedDudeWithWire className="animate-spin" />
</div>
<h1 className="text-6xl font-alpha calt mb-10">{title}</h1>
{Object.keys(messages).includes(code.toString()) ? (
<p className="text-lg mb-10">{messages[code]}</p>
) : null}
<p className="text-lg mb-10">
<RainbowButton
onClick={() => navigate('..')}
variant="border"
className="text-xs"
>
Go back and try again
</RainbowButton>
</p>
</LayoutWithSky>
);
};
@@ -0,0 +1,70 @@
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
export const Dude = ({ className }: HTMLAttributes<SVGElement>) => {
return (
<svg
width="41"
height="47"
viewBox="0 0 41 47"
fill="none"
className={className}
>
<path
d="M21.1895 0.298767L5.08827 27.4101L8.96133 29.7103L4.36099 37.4564L8.23404 39.7566L12.8344 32.0105L16.7074 34.3107L12.1071 42.0568L15.9801 44.3569L20.5805 36.6108L24.4535 38.911L40.5547 11.7996L21.1895 0.298767Z"
className="fill-black dark:fill-white"
/>
<path
d="M35.9346 15.1683L20.4424 5.96765L14.3086 16.2958L29.8008 25.4965L35.9346 15.1683Z"
className="fill-white dark:fill-black"
/>
<path
d="M25.646 17.7895L23.064 16.2561L21.5305 18.8381L24.1126 20.3716L25.646 17.7895Z"
className="fill-black dark:fill-white"
/>
<path
d="M29.7612 16.7412L27.1792 15.2077L25.6458 17.7898L28.2278 19.3232L29.7612 16.7412Z"
className="fill-black dark:fill-white"
/>
<path
d="M33.877 15.6925L31.2949 14.159L29.7615 16.7411L32.3435 18.2745L33.877 15.6925Z"
className="fill-black dark:fill-white"
/>
<path
d="M29.0342 26.7874L26.4521 25.2539L24.9187 27.836L27.5007 29.3694L29.0342 26.7874Z"
fill="#FF077F"
/>
</svg>
);
};
export const Wire = ({ className }: HTMLAttributes<SVGElement>) => {
return (
<svg
width="157"
height="88"
viewBox="0 0 157 88"
fill="none"
className={className}
>
<path
d="M109.398 6.12235C127.37 -3.81898 146.791 1.45045 153.465 14.307C160.138 27.1636 154.195 43.9948 140.438 52.1164C126.68 60.238 105.767 54.9998 84.9212 43.464C64.0752 31.9281 32.2412 6.42016 18.8175 24.185C6.90871 40.719 41.9332 68.4495 29.2664 82.7049C23.187 88.4974 11.1379 88.2645 0.968295 80.3398"
className="stroke-black dark:stroke-white"
strokeWidth="1.5"
strokeMiterlimit="10"
/>
</svg>
);
};
export const AnimatedDudeWithWire = ({ className }: { className?: string }) => (
<div className="relative">
<Wire className="absolute top-[25px]" />
<Dude
className={classNames(
'absolute left-[96px] animate-[wave_20s_ease-in-out_infinite]',
className
)}
/>
</div>
);
@@ -0,0 +1,52 @@
import { Table } from './table';
export const HowItWorksTable = () => (
<Table
className="bg-none bg-vega-clight-800 dark:bg-vega-cdark-800"
noHeader
noCollapse
columns={[{ name: 'number', className: 'px-0 pl-5' }, { name: 'step' }]}
data={[
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
1
</span>
),
step: 'Referrers generate a code assigned to their key via an on chain transaction',
},
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
2
</span>
),
step: 'Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction',
},
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
3
</span>
),
step: 'Discounts are applied automatically during trading based on the key(s) used',
},
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
4
</span>
),
step: 'Referrers earn commission based on a percentage of the taker fees their referees pay',
},
{
number: (
<span className="text-2xl calt text-vega-clight-100 dark:text-vega-cdark-100">
5
</span>
),
step: 'The commission is taken from the infrastructure fee, maker fee, and liquidity provider fee, not from the referee',
},
]}
></Table>
);
@@ -0,0 +1,31 @@
import classNames from 'classnames';
import { AnimatedDudeWithWire } from './graphics/dude';
export const LandingBanner = () => {
return (
<div className={classNames('relative mb-20')}>
<div className="">
<div
aria-hidden
className="absolute top-64 right-[220px] md:right-[340px] max-sm:hidden"
>
<AnimatedDudeWithWire />
</div>
<div className="pt-32 sm:w-[50%]">
<h1 className="text-6xl font-alpha calt mb-10">
Earn commission & stake rewards
</h1>
<p className="text-lg mb-10">
Invite friends and earn commission in the form of Vega rewards from
the trading fees they pay. Stake those rewards to earn multipliers
on future rewards.
</p>
<p className="text-lg">
Any friends that join using the code will receive discounts off
trading fees.
</p>
</div>
</div>
</div>
);
};
@@ -0,0 +1,36 @@
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { SKY_BACKGROUND } from './constants';
import { Outlet } from 'react-router-dom';
export const Layout = ({
className,
children,
...props
}: HTMLAttributes<HTMLDivElement>) => {
return (
<div
className={classNames(
'max-w-[1440px]',
'mx-auto px-4 md:px-32 lg:px-16 pb-32',
'relative z-0',
'h-full overflow-auto',
className
)}
{...props}
>
{children || <Outlet />}
</div>
);
};
export const LayoutWithSky = ({
className,
...props
}: HTMLAttributes<HTMLDivElement>) => {
return (
<div className={classNames('h-full', SKY_BACKGROUND)}>
<Layout className={className} {...props} />
</div>
);
};
@@ -0,0 +1,79 @@
import { Tile } from './tile';
import {
CopyWithTooltip,
Input,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import { Button } from './buttons';
import { Tag } from './tag';
export const ReferralStatistics = () => {
return (
<div className="grid grid-cols-1 grid-rows-1 gap-5">
<div className="grid lg:grid-cols-3 grid-rows-3 lg:grid-rows-1 gap-5">
<Tile>
<h3 className="mb-1 text-4xl text-center">3</h3>
<p className="mb-3 text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
Your referral tier
</p>
<Tag className="mx-auto" color="purple">
10,000 until Tier 2
</Tag>
</Tile>
<Tile>
<h3 className="mb-1 text-4xl text-center">0.1%</h3>
<p className="mb-3 text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
Your commission
</p>
<Tag className="mx-auto" color="purple">
10,000 until 0.5%x
</Tag>
</Tile>
<Tile variant="rainbow">
<h3 className="mb-1 text-lg calt">Your referral code</h3>
<p className="mb-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
Share this code with friends
</p>
<div className="flex gap-2">
<Input size={1} readOnly value="1234567890" />
<CopyWithTooltip text="1234567890">
<Button
className="text-sm no-underline"
icon={<VegaIcon name={VegaIconNames.COPY} />}
>
<span>Copy</span>
</Button>
</CopyWithTooltip>
</div>
</Tile>
</div>
<div className="grid grid-cols-2 lg:grid-cols-4 grid-rows-1 gap-5">
<Tile className="py-3">
<h3 className="mb-1 text-2xl text-center">10,000</h3>
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
Your total trading volume
</p>
</Tile>
<Tile className="py-3">
<h3 className="mb-1 text-2xl text-center">7</h3>
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
Total traders referred
</p>
</Tile>
<Tile className="py-3">
<h3 className="mb-1 text-2xl text-center">0.1%</h3>
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
Maximum trader discount
</p>
</Tile>
<Tile className="py-3">
<h3 className="mb-1 text-2xl text-center">10,000</h3>
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
Your commission (last 30d)
</p>
</Tile>
</div>
</div>
);
};
@@ -0,0 +1,148 @@
import {
TradingAnchorButton,
VegaIcon,
VegaIconNames,
} from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import { HowItWorksTable } from './how-it-works-table';
import { LandingBanner } from './landing-banner';
import { TiersTable } from './tiers-table';
import { BORDER_COLOR, GRADIENT } from './constants';
import { RainbowTabLink } from './buttons';
import { Outlet } from 'react-router-dom';
import { Tag } from './tag';
import { Routes } from '../../pages/client-router';
export const Referrals = () => {
return (
<>
<LandingBanner />
<div>
<div className="flex justify-center">
<RainbowTabLink end to={Routes.REFERRALS}>
Your referrals
</RainbowTabLink>
<RainbowTabLink to={Routes.REFERRALS_CREATE_CODE}>
Your referrals
</RainbowTabLink>
<RainbowTabLink to={Routes.REFERRALS_APPLY_CODE}>
Apply a code
</RainbowTabLink>
</div>
<div className="py-16 border-t border-b border-vega-cdark-500">
<Outlet />
</div>
</div>
<div className="flex flex-row items-baseline justify-between mt-10 mb-5">
<h2 className="text-2xl">Referral tiers</h2>
<span className="text-base">
<span className="text-vega-clight-200 dark:text-vega-cdark-200">
Program ends:
</span>{' '}
16 epochs
</span>
</div>
<div className="mb-20">
<TiersTable />
</div>
<div className="flex flex-row items-baseline justify-between mb-5">
<h2 className="text-2xl">Staking multipliers</h2>
</div>
<div className="flex flex-col mb-20 jjustify-items-stretch md:flex-row gap-5">
<div
className={classNames(
'overflow-hidden',
'border rounded-md w-full',
BORDER_COLOR
)}
>
<div aria-hidden>
<img
src="/1x.png"
alt="1x multiplier"
width={768}
height={400}
className="w-full"
/>
</div>
<div className={classNames('p-3', GRADIENT)}>
<h3 className="mb-3 text-xl">Tradestarter</h3>
<p className="text-base text-vega-clight-100 dark:text-vega-cdark-100">
Stake a minimum of 100 $VEGA tokens
</p>
<Tag color="green">Reward multiplier 1x</Tag>
</div>
</div>
<div
className={classNames(
'overflow-hidden',
'border rounded-md w-full',
BORDER_COLOR
)}
>
<div aria-hidden>
<img
src="/2x.png"
alt="2x multiplier"
width={768}
height={400}
className="w-full"
/>
</div>
<div className={classNames('p-3', GRADIENT)}>
<h3 className="mb-3 text-xl">Mid level degen</h3>
<p className="text-base text-vega-clight-100 dark:text-vega-cdark-100">
Stake a minimum of 1000 $VEGA tokens
</p>
<Tag color="blue">Reward multiplier 2x</Tag>
</div>
</div>
<div
className={classNames(
'overflow-hidden',
'border rounded-md w-full',
BORDER_COLOR
)}
>
<div aria-hidden>
<img
src="/3x.png"
alt="3x multiplier"
width={768}
height={400}
className="w-full"
/>
</div>
<div className={classNames('p-3', GRADIENT)}>
<h3 className="mb-3 text-xl">Reward hoarder</h3>
<p className="text-base text-vega-clight-100 dark:text-vega-cdark-100">
Stake a minimum of 10,000 $VEGA tokens
</p>
<Tag color="pink">Reward multiplier 3x</Tag>
</div>
</div>
</div>
<div className="mt-10 mb-5 text-center">
<h2 className="text-2xl">How it works</h2>
</div>
<div className="md:w-[60%] mx-auto">
<HowItWorksTable />
<div className="mt-5">
<TradingAnchorButton
className="mx-auto w-max"
href="https://docs.vega.xyz/"
target="_blank"
>
Read the terms <VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
</TradingAnchorButton>
</div>
</div>
</>
);
};
export default Referrals;
@@ -0,0 +1,116 @@
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { BORDER_COLOR, GRADIENT } from './constants';
type TableColumnDefinition = {
displayName?: string;
name: string;
tooltip?: string;
className?: string;
};
type TableProps = {
columns: TableColumnDefinition[];
data: Record<TableColumnDefinition['name'] | 'className', React.ReactNode>[];
noHeader?: boolean;
noCollapse?: boolean;
};
const INNER_BORDER_STYLE = `border-b ${BORDER_COLOR}`;
export const Table = ({
columns,
data,
noHeader = false,
noCollapse = false,
className,
...props
}: TableProps & HTMLAttributes<HTMLTableElement>) => {
const header = (
<thead className={classNames({ 'max-md:hidden': !noCollapse })}>
<tr>
{columns.map(({ displayName, name, tooltip }) => (
<th
key={name}
col-id={name}
className={classNames(
'px-5 py-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100',
INNER_BORDER_STYLE
)}
>
<span className="flex flex-row gap-2 items-center">
<span>{displayName}</span>
{tooltip ? (
<Tooltip description={tooltip}>
<button className="text-vega-clight-400 dark:text-vega-cdark-400 no-underline decoration-transparent w-[12px] h-[12px] inline-flex">
<VegaIcon size={12} name={VegaIconNames.INFO} />
</button>
</Tooltip>
) : null}
</span>
</th>
))}
</tr>
</thead>
);
return (
<table
className={classNames(
'w-full',
'border-separate border rounded-md border-spacing-0',
BORDER_COLOR,
GRADIENT,
className
)}
{...props}
>
{!noHeader && header}
<tbody>
{data.map((d, i) => (
<tr
key={i}
className={classNames(d['className'] as string, {
'max-md:flex flex-col w-full': !noCollapse,
})}
>
{columns.map(({ name, displayName, className }, j) => (
<td
className={classNames(
'px-5 py-3 text-base',
{
'max-md:flex max-md:flex-col max-md:justify-between':
!noCollapse,
},
INNER_BORDER_STYLE,
{
'border-none': i === data.length - 1 && noCollapse,
'md:border-none': i === data.length - 1,
'max-md:border-none':
i === data.length - 1 && j === columns.length - 1,
},
className
)}
key={`${i}-${name}`}
>
{/** display column name in mobile view */}
{!noCollapse &&
!noHeader &&
displayName &&
displayName.length > 0 && (
<span
aria-hidden
className="md:hidden font-mono text-xs px-0 text-vega-clight-100 dark:text-vega-cdark-100"
>
{displayName}
</span>
)}
<span>{d[name]}</span>
</td>
))}
</tr>
))}
</tbody>
</table>
);
};
@@ -0,0 +1,32 @@
import type { HTMLAttributes } from 'react';
import classNames from 'classnames';
type TagProps = {
color?: 'yellow' | 'green' | 'blue' | 'purple' | 'pink' | 'orange' | 'none';
};
export const Tag = ({
color = 'none',
children,
className,
...props
}: TagProps & HTMLAttributes<HTMLDivElement>) => (
<div
className={classNames(
'mt-3 w-max border rounded-[1rem] py-[0.125rem] px-2 text-xs',
{
'border-vega-yellow-500 text-vega-yellow-500': color === 'yellow',
'border-vega-green-500 text-vega-green-500': color === 'green',
'border-vega-blue-500 text-vega-blue-500': color === 'blue',
'border-vega-purple-500 text-vega-purple-500': color === 'purple',
'border-vega-pink-500 text-vega-pink-500': color === 'pink',
'border-vega-orange-500 text-vega-orange-500': color === 'orange',
'border-vega-clight-100 text-vega-clight-100 dark:border-vega-cdark-100 dark:text-vega-cdark-100':
color === 'none',
},
className
)}
{...props}
>
{children}
</div>
);
@@ -0,0 +1,42 @@
import { Table } from './table';
export const TiersTable = () => (
<Table
columns={[
{ name: 'tier', displayName: 'Tier' },
{
name: 'commission',
displayName: 'Referrer commission',
tooltip: 'A percentage of commission earned by the referrer',
},
{ name: 'discount', displayName: 'Referrer trading discount' },
{ name: 'volume', displayName: 'Min. trading volume' },
]}
data={[
{
tier: '1',
commission: '1.0%',
discount: '1.0%',
volume: '€30,000',
className:
'from-vega-pink-400 dark:from-vega-pink-600 to-20% bg-highlight',
},
{
tier: '2',
commission: '0.5%',
discount: '0.5%',
volume: '€20,000',
className:
'from-vega-purple-400 dark:from-vega-purple-600 to-20% bg-highlight',
},
{
tier: '3',
commission: '0.1%',
discount: '0.1%',
volume: '€10,000',
className:
'from-vega-blue-400 dark:from-vega-blue-600 to-20% bg-highlight',
},
]}
></Table>
);
@@ -0,0 +1,39 @@
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { BORDER_COLOR, GRADIENT } from './constants';
type TileProps = {
variant?: 'rainbow' | 'default';
};
export const Tile = ({
variant = 'default',
className,
children,
}: TileProps & HTMLAttributes<HTMLDivElement>) => {
return (
<div
className={classNames(
{
'bg-rainbow p-[0.125rem]': variant === 'rainbow',
[`border-2 ${BORDER_COLOR} p-0`]: variant === 'default',
},
'rounded-lg overflow-hidden'
)}
>
<div
className={classNames(
{
'bg-white dark:bg-vega-cdark-900 text-black dark:text-white rounded-[0.35rem] overflow-hidden':
variant === 'rainbow',
},
'p-6',
GRADIENT,
className
)}
>
{children}
</div>
</div>
);
};
@@ -180,6 +180,11 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
{t('Trading')}
</NavbarLink>
</NavbarItem>
<NavbarItem>
<NavbarLink to={Links[Routes.REFERRALS]()} onClick={onClick}>
{t('Referrals')}
</NavbarLink>
</NavbarItem>
<NavbarItem>
<NavbarLink to={Links[Routes.PORTFOLIO]()} onClick={onClick}>
{t('Portfolio')}
+43
View File
@@ -6,6 +6,10 @@ import { t } from '@vegaprotocol/i18n';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import trimEnd from 'lodash/trimEnd';
import { LayoutWithSidebar } from '../components/layouts';
import { LayoutWithSky } from '../client-pages/referrals/layout';
import { ReferralStatistics } from '../client-pages/referrals/referral-statistics';
import { ApplyCodeForm } from '../client-pages/referrals/apply-code-form';
import { CreateCodeForm } from '../client-pages/referrals/create-code-form';
const LazyHome = dynamic(() => import('../client-pages/home'), {
ssr: false,
@@ -35,6 +39,13 @@ const LazyDeposit = dynamic(() => import('../client-pages/deposit'), {
ssr: false,
});
const LazyReferrals = dynamic(
() => import('../client-pages/referrals/referrals'),
{
ssr: false,
}
);
export enum Routes {
HOME = '/',
MARKET = '/markets/:marketId',
@@ -43,6 +54,10 @@ export enum Routes {
LIQUIDITY = '/liquidity/:marketId',
DISCLAIMER = '/disclaimer',
DEPOSIT = '/deposit',
REFERRALS = '/referrals',
REFERRALS_APPLY_CODE = '/referrals/apply-code',
REFERRALS_CREATE_CODE = '/referrals/create-code',
TEAMS = '/teams',
}
type ConsoleLinks = { [r in Routes]: (...args: string[]) => string };
@@ -57,6 +72,10 @@ export const Links: ConsoleLinks = {
trimEnd(Routes.LIQUIDITY.replace(':marketId', marketId)),
[Routes.DISCLAIMER]: () => Routes.DISCLAIMER,
[Routes.DEPOSIT]: () => Routes.DEPOSIT,
[Routes.REFERRALS]: () => Routes.REFERRALS,
[Routes.REFERRALS_APPLY_CODE]: () => Routes.REFERRALS_APPLY_CODE,
[Routes.REFERRALS_CREATE_CODE]: () => Routes.REFERRALS_CREATE_CODE,
[Routes.TEAMS]: () => Routes.TEAMS,
};
export const routerConfig: RouteObject[] = [
@@ -109,6 +128,30 @@ export const routerConfig: RouteObject[] = [
element: <LazyDisclaimer />,
},
{ path: Routes.DEPOSIT, element: <LazyDeposit /> },
// Referrals routing:
{
path: Routes.REFERRALS,
element: <LayoutWithSky />,
children: [
{
element: <LazyReferrals />,
children: [
{
index: true,
element: <ReferralStatistics />,
},
{
path: Routes.REFERRALS_APPLY_CODE,
element: <ApplyCodeForm />,
},
{
path: Routes.REFERRALS_CREATE_CODE,
element: <CreateCodeForm />,
},
],
},
],
},
{
path: '*',
element: (
Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 KiB

+31 -1
View File
@@ -13,7 +13,37 @@ module.exports = {
],
darkMode: 'class',
theme: {
extend: theme,
extend: {
...theme,
colors: {
transparent: 'transparent',
current: 'currentColor',
...theme.colors,
},
backgroundImage: {
...theme.backgroundImage,
rainbow:
'linear-gradient(103.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
'rainbow-shifted':
'linear-gradient(103.47deg, #0075FF 1.68%, #8028FF 47.49%, #FF077F 100%)',
highlight:
'linear-gradient(170deg, var(--tw-gradient-from), transparent var(--tw-gradient-to-position))',
},
keyframes: {
...theme.keyframes,
shake: {
'0%': { transform: 'translateX(0)' },
'25%': { transform: 'translateX(5px)' },
'50%': { transform: 'translateX(-5px)' },
'75%': { transform: 'translateX(5px)' },
'100%': { transform: 'translateX(0)' },
},
},
animation: {
...theme.animation,
shake: 'shake 200ms linear',
},
},
},
plugins: [vegaCustomClasses],
};
+6 -2
View File
@@ -96,11 +96,15 @@ export const calcTradedFactor = (m: MarketMaybeWithDataAndCandles) => {
const volume = Number(calcCandleVolume(m.candles || []) || 0);
const price = m.data?.markPrice ? Number(m.data.markPrice) : 0;
const quantum = Number(
m.tradableInstrument.instrument.product.settlementAsset.quantum
m.tradableInstrument.instrument.product.settlementAsset?.quantum
);
const decimals = Number(
m.tradableInstrument.instrument.product.settlementAsset.decimals
m.tradableInstrument.instrument.product.settlementAsset?.decimals
);
// `settlementAsset` can be undefined hence there's no quantum or decimals
if (isNaN(quantum) || isNaN(decimals)) return 0;
const fp = toBigNum(price, decimals);
const fq = toBigNum(quantum, decimals);
const factor = fq.multipliedBy(fp).multipliedBy(volume);
+21 -1
View File
@@ -388,6 +388,24 @@ export interface TransferBody {
transfer: Transfer;
}
export type ApplyReferralCode = {
applyReferralCode: {
id: string;
};
};
export type CreateReferralSet = {
createReferralSet: {
isTeam: boolean;
team?: {
name: string;
teamUrl?: string;
avatarUrl?: string;
closed: boolean;
};
};
};
export type Transaction =
| StopOrdersSubmissionBody
| StopOrdersCancellationBody
@@ -401,7 +419,9 @@ export type Transaction =
| ProposalSubmissionBody
| BatchMarketInstructionSubmissionBody
| TransferBody
| LiquidityProvisionSubmission;
| LiquidityProvisionSubmission
| ApplyReferralCode
| CreateReferralSet;
export const isWithdrawTransaction = (
transaction: Transaction
+1 -1
View File
@@ -212,7 +212,7 @@
"style-loader": "^3.3.0",
"stylus": "^0.55.0",
"stylus-loader": "^7.1.0",
"tailwindcss": "3.2.7",
"tailwindcss": "3.3.3",
"ts-jest": "29.1.0",
"ts-node": "10.9.1",
"tslib": "^2.3.0",
+159 -63
View File
@@ -7,6 +7,11 @@
resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.0.1.tgz#b38b444ad3aa5fedbb15f2f746dcd934226a12dd"
integrity sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==
"@alloc/quick-lru@^5.2.0":
version "5.2.0"
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
"@ampproject/remapping@^2.1.0", "@ampproject/remapping@^2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
@@ -9629,16 +9634,7 @@ acorn-jsx@^5.3.1, acorn-jsx@^5.3.2:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn-node@^1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8"
integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==
dependencies:
acorn "^7.0.0"
acorn-walk "^7.0.0"
xtend "^4.0.2"
acorn-walk@^7.0.0, acorn-walk@^7.2.0:
acorn-walk@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
@@ -9648,7 +9644,7 @@ acorn-walk@^8.0.2, acorn-walk@^8.1.1, acorn-walk@^8.2.0:
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^7.0.0, acorn@^7.4.1:
acorn@^7.4.1:
version "7.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
@@ -9899,6 +9895,11 @@ any-observable@^0.3.0:
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b"
integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==
any-promise@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
anymatch@^3.0.3, anymatch@~3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
@@ -12972,11 +12973,6 @@ define-properties@^1.2.0:
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
integrity sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==
defu@^6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.2.tgz#1217cba167410a1765ba93893c6dbac9ed9d9e5c"
@@ -13088,15 +13084,6 @@ detect-port@^1.3.0, detect-port@^1.5.1:
address "^1.0.1"
debug "4"
detective@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034"
integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==
dependencies:
acorn-node "^1.8.2"
defined "^1.0.0"
minimist "^1.2.6"
didyoumean@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
@@ -15330,6 +15317,18 @@ glob@7.1.4:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@7.1.7, glob@~7.1.1:
version "7.1.7"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
@@ -16401,6 +16400,13 @@ is-core-module@^2.11.0:
dependencies:
has "^1.0.3"
is-core-module@^2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
dependencies:
has "^1.0.3"
is-core-module@^2.5.0, is-core-module@^2.8.1:
version "2.10.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
@@ -17443,6 +17449,11 @@ jest@29.4.3:
import-local "^3.0.2"
jest-cli "^29.4.3"
jiti@^1.18.2:
version "1.20.0"
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42"
integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==
js-sha3@0.8.0, js-sha3@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
@@ -17888,7 +17899,7 @@ lilconfig@^2.0.3, lilconfig@^2.1.0:
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
lilconfig@^2.0.5, lilconfig@^2.0.6:
lilconfig@^2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4"
integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==
@@ -19278,6 +19289,15 @@ mute-stream@0.0.8:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
mz@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
dependencies:
any-promise "^1.0.0"
object-assign "^4.0.1"
thenify-all "^1.0.0"
nanoid@3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
@@ -19630,7 +19650,7 @@ nx@16.4.0:
"@nx/nx-win32-arm64-msvc" "16.4.0"
"@nx/nx-win32-x64-msvc" "16.4.0"
object-assign@^4.1.0, object-assign@^4.1.1:
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
@@ -20370,6 +20390,11 @@ pino@7.11.0:
sonic-boom "^2.2.1"
thread-stream "^0.15.1"
pirates@^4.0.1:
version "4.0.6"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
pirates@^4.0.4, pirates@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b"
@@ -20519,7 +20544,16 @@ postcss-discard-overridden@^6.0.0:
resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz#49c5262db14e975e349692d9024442de7cd8e234"
integrity sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==
postcss-import@^14.1.0, postcss-import@~14.1.0:
postcss-import@^15.1.0:
version "15.1.0"
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70"
integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==
dependencies:
postcss-value-parser "^4.0.0"
read-cache "^1.0.0"
resolve "^1.1.7"
postcss-import@~14.1.0:
version "14.1.0"
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
@@ -20528,14 +20562,14 @@ postcss-import@^14.1.0, postcss-import@~14.1.0:
read-cache "^1.0.0"
resolve "^1.1.7"
postcss-js@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00"
integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
postcss-js@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
dependencies:
camelcase-css "^2.0.1"
postcss-load-config@^3.0.0, postcss-load-config@^3.1.4:
postcss-load-config@^3.0.0:
version "3.1.4"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855"
integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
@@ -20543,6 +20577,14 @@ postcss-load-config@^3.0.0, postcss-load-config@^3.1.4:
lilconfig "^2.0.5"
yaml "^1.10.2"
postcss-load-config@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd"
integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==
dependencies:
lilconfig "^2.0.5"
yaml "^2.1.1"
postcss-loader@^6.1.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef"
@@ -20703,12 +20745,12 @@ postcss-modules@^4.0.0:
postcss-modules-values "^4.0.0"
string-hash "^1.1.1"
postcss-nested@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735"
integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==
postcss-nested@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c"
integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==
dependencies:
postcss-selector-parser "^6.0.10"
postcss-selector-parser "^6.0.11"
postcss-normalize-charset@^5.1.0:
version "5.1.0"
@@ -20881,14 +20923,6 @@ postcss-reduce-transforms@^6.0.0:
dependencies:
postcss-value-parser "^4.2.0"
postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
version "6.0.10"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
dependencies:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9:
version "6.0.13"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b"
@@ -20897,6 +20931,14 @@ postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.5, postcss-selecto
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
version "6.0.10"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
dependencies:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-svgo@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d"
@@ -20955,7 +20997,7 @@ postcss@8.4.21:
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.0.9, postcss@^8.4.14, postcss@^8.4.21, postcss@^8.4.24:
postcss@^8.4.14, postcss@^8.4.21, postcss@^8.4.24:
version "8.4.24"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df"
integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==
@@ -20964,6 +21006,15 @@ postcss@^8.0.9, postcss@^8.4.14, postcss@^8.4.21, postcss@^8.4.24:
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.4.23:
version "8.4.29"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd"
integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
preact@10.4.1:
version "10.4.1"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.1.tgz#9b3ba020547673a231c6cf16f0fbaef0e8863431"
@@ -22133,6 +22184,15 @@ resolve@^1.17.0:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^1.22.2:
version "1.22.6"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362"
integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==
dependencies:
is-core-module "^2.13.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^2.0.0-next.3, resolve@^2.0.0-next.4:
version "2.0.0-next.4"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660"
@@ -23475,6 +23535,19 @@ stylus@^0.59.0:
sax "~1.2.4"
source-map "^0.7.3"
sucrase@^3.32.0:
version "3.34.0"
resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.34.0.tgz#1e0e2d8fcf07f8b9c3569067d92fbd8690fb576f"
integrity sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.2"
commander "^4.0.0"
glob "7.1.6"
lines-and-columns "^1.1.6"
mz "^2.7.0"
pirates "^4.0.1"
ts-interface-checker "^0.1.9"
superstruct@^0.14.2:
version "0.14.2"
resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b"
@@ -23600,34 +23673,33 @@ table@6.8.0:
string-width "^4.2.3"
strip-ansi "^6.0.1"
tailwindcss@3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.2.7.tgz#5936dd08c250b05180f0944500c01dce19188c07"
integrity sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==
tailwindcss@3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf"
integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==
dependencies:
"@alloc/quick-lru" "^5.2.0"
arg "^5.0.2"
chokidar "^3.5.3"
color-name "^1.1.4"
detective "^5.2.1"
didyoumean "^1.2.2"
dlv "^1.1.3"
fast-glob "^3.2.12"
glob-parent "^6.0.2"
is-glob "^4.0.3"
lilconfig "^2.0.6"
jiti "^1.18.2"
lilconfig "^2.1.0"
micromatch "^4.0.5"
normalize-path "^3.0.0"
object-hash "^3.0.0"
picocolors "^1.0.0"
postcss "^8.0.9"
postcss-import "^14.1.0"
postcss-js "^4.0.0"
postcss-load-config "^3.1.4"
postcss-nested "6.0.0"
postcss "^8.4.23"
postcss-import "^15.1.0"
postcss-js "^4.0.1"
postcss-load-config "^4.0.1"
postcss-nested "^6.0.1"
postcss-selector-parser "^6.0.11"
postcss-value-parser "^4.2.0"
quick-lru "^5.1.1"
resolve "^1.22.1"
resolve "^1.22.2"
sucrase "^3.32.0"
tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
version "2.2.1"
@@ -23790,6 +23862,20 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
thenify-all@^1.0.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
dependencies:
thenify ">= 3.1.0 < 4"
"thenify@>= 3.1.0 < 4":
version "3.3.1"
resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
dependencies:
any-promise "^1.0.0"
thread-stream@^0.15.1:
version "0.15.2"
resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-0.15.2.tgz#fb95ad87d2f1e28f07116eb23d85aba3bc0425f4"
@@ -23954,6 +24040,11 @@ ts-dedent@^2.0.0, ts-dedent@^2.2.0:
resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==
ts-interface-checker@^0.1.9:
version "0.1.13"
resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
ts-invariant@^0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.10.3.tgz#3e048ff96e91459ffca01304dbc7f61c1f642f6c"
@@ -25172,7 +25263,7 @@ xmlchars@^2.2.0:
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1:
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
@@ -25212,6 +25303,11 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yaml@^2.1.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144"
integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==
yargs-parser@20.2.4:
version "20.2.4"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"