Skip to content

Commit

Permalink
Governance Template UI (#1848)
Browse files Browse the repository at this point in the history
  • Loading branch information
vutuanlinh2k2 authored Nov 25, 2023
1 parent 56d2559 commit c5f1330
Show file tree
Hide file tree
Showing 13 changed files with 640 additions and 591 deletions.
561 changes: 288 additions & 273 deletions libs/webb-ui-components/src/components/ChainsRing/ChainsRing.tsx

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion libs/webb-ui-components/src/components/ChainsRing/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './ChainsRing';
import { default as ChainsRing } from './ChainsRing';

export default ChainsRing;
38 changes: 0 additions & 38 deletions libs/webb-ui-components/src/components/ChainsRing/types.d.ts

This file was deleted.

13 changes: 13 additions & 0 deletions libs/webb-ui-components/src/components/ChainsRing/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { PropsOf } from '../../types';

export interface ChainsRingProps extends PropsOf<'div'> {
circleContent?: React.ReactNode;
additionalSvgContent?: React.ReactNode;
chainItems: Array<ChainItem | undefined>;
}

export type ChainItem = {
typedChainId: number;
onClick?: () => void;
isActive?: boolean;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { FC } from 'react';
import cx from 'classnames';
import { ArrowDropDownFill } from '@webb-tools/icons';

import {
Accordion,
AccordionButtonBase,
AccordionContent,
AccordionItem,
} from '../Accordion';
import { Button } from '../buttons';
import { Input } from '../Input';
import { Typography } from '../../typography/Typography';
import { FunctionInfoType } from './types';

const FunctionInputs: FC<{ fncInfo: FunctionInfoType }> = ({ fncInfo }) => {
const { fncName, fncParams } = fncInfo;
return (
<Accordion
type="single"
collapsible
className="w-full bg-[#F7F8F7]/80 dark:bg-mono-180 rounded-lg"
>
<AccordionItem value={fncName}>
<AccordionButtonBase className="w-full group flex items-center justify-between">
<Typography variant="h5" fw="bold">
{fncName}
</Typography>

<ArrowDropDownFill
size="lg"
className={cx(
'ml-2 fill-mono-120 dark:fill-mono-100 duration-300',
'group-radix-state-open:rotate-180',
'group-radix-state-closed:rotate-0'
)}
/>
</AccordionButtonBase>

<AccordionContent
className={cx(
'overflow-hidden',
'radix-state-open:animate-accordion-slide-down',
'radix-state-closed:animate-accordion-slide-up'
)}
>
<div className="flex flex-col items-end gap-2">
{fncParams.map((param) => {
const { name, type } = param;
return (
<div className="w-full flex items-center justify-end gap-2">
<Typography variant="body1">{name}: </Typography>
<Input
id={`${fncName}-${name}`}
className="w-[75%]"
placeholder={type}
/>
</div>
);
})}

<Button className="!rounded-lg">Submit</Button>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
);
};

export default FunctionInputs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { type FC, useCallback, useMemo, useState } from 'react';
import { getAbiItem } from 'viem';
import cx from 'classnames';
import { chainsConfig } from '@webb-tools/dapp-config/chains/chain-config';

import ChainsRing from '../ChainsRing';
import FunctionInputs from './FunctionInputs';
import { Typography } from '../../typography';
import type { GovernanceFormProps, FunctionInfoType } from './types';
import type { ChainItem } from '../ChainsRing/types';

const GovernanceForm: FC<GovernanceFormProps> = ({
abi,
typedChainIdSelections,
governanceFncNames,
}) => {
const [selectedTypedChainId, setSelectedTypedChainId] = useState<
number | undefined
>();

const fncInfos = useMemo<FunctionInfoType[]>(
() =>
governanceFncNames.map((fncName) => {
const item = getAbiItem({
abi,
name: fncName,
});
return {
fncName: item.name,
fncParams: item.inputs.map((input) => ({
name: input.name,
type: input.type,
})),
};
}),
[abi, governanceFncNames]
);

const chainRingItems = useMemo<ChainItem[]>(
() =>
typedChainIdSelections.map((typedChainId) => {
return {
typedChainId,
isActive: selectedTypedChainId === typedChainId,
onClick: () => handleSelectedChain(typedChainId),
};
}),
[typedChainIdSelections, selectedTypedChainId]
);

const handleSelectedChain = useCallback((typedChainId: number) => {
setSelectedTypedChainId(typedChainId);
}, []);

return (
<div
className={cx(
'max-w-[600px] bg-mono-0 dark:bg-mono-190 rounded-xl p-9',
'flex flex-col items-center gap-6',
'border border-mono-40 dark:border-mono-160'
)}
>
{/* Chains Ring */}
<ChainsRing
chainItems={chainRingItems}
circleContent={
<div>
<Typography
variant="body1"
fw="bold"
ta="center"
className="text-mono-140 dark:text-mono-80 capitalize"
>
{selectedTypedChainId !== undefined
? chainsConfig[selectedTypedChainId].name
: 'Select Chain'}
</Typography>
</div>
}
/>

{/* Form */}
<div className="space-y-3 w-full">
{fncInfos.map((fncInfo) => (
<FunctionInputs fncInfo={fncInfo} />
))}
</div>
</div>
);
};

export default GovernanceForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { default as GovernanceForm } from './GovernanceForm';

export default GovernanceForm;
15 changes: 15 additions & 0 deletions libs/webb-ui-components/src/components/GovernanceForm/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Abi } from 'viem';

export interface GovernanceFormProps {
abi: Abi;
typedChainIdSelections: number[];
governanceFncNames: string[];
}

export type FunctionInfoType = {
fncName: string;
fncParams: {
name?: string;
type: string;
}[];
};
40 changes: 40 additions & 0 deletions libs/webb-ui-components/src/components/GovernanceForm/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export const MAX_NUM_OF_CHAINS = 8;

export function getChainIconClassNameByIdx(idx: number) {
const baseClassName = 'absolute';
let positionClassName = '';
switch (idx % MAX_NUM_OF_CHAINS) {
case 0:
positionClassName = 'top-1/2 translate-y-[-50%] left-[105.5px]';
break;
case 1:
positionClassName =
'rotate-45 top-[40px] translate-y-[-50%] left-[131.5px]';
break;
case 2:
positionClassName = 'top-[2px] translate-x-[50%] right-1/2';
break;
case 3:
positionClassName =
'-rotate-45 top-[40px] translate-y-[-50%] right-[132.5px]';
break;
case 4:
positionClassName = 'top-1/2 translate-y-[-50%] right-[105.5px]';
break;
case 5:
positionClassName =
'-rotate-45 bottom-[16.75px] translate-y-[-50%] right-[132.2575px]';
break;
case 6:
positionClassName = 'bottom-[2px] translate-x-[50%] right-1/2';
break;
case 7:
positionClassName =
'rotate-45 bottom-[17px] translate-y-[-50%] left-[131.5px]';
break;
default:
break;
}

return `${baseClassName} ${positionClassName}`;
}
Loading

0 comments on commit c5f1330

Please sign in to comment.