Skip to content

Commit

Permalink
feat(hooks-store): style hook details (#4932)
Browse files Browse the repository at this point in the history
  • Loading branch information
fairlighteth authored Oct 4, 2024
1 parent 5fb7f34 commit 83184d2
Show file tree
Hide file tree
Showing 15 changed files with 472 additions and 125 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,67 @@
import { useState } from 'react'

import { HookToDappMatch } from '@cowprotocol/hook-dapp-lib'

import { Item, Wrapper } from './styled'
import { ChevronDown, ChevronUp } from 'react-feather'

import { clickOnHooks } from 'modules/analytics'

import * as styledEl from './styled'

export function HookItem({ item, index }: { item: HookToDappMatch; index: number }) {
const [isOpen, setIsOpen] = useState(false)

const handleLinkClick = () => {
clickOnHooks(item.dapp?.name || 'Unknown hook dapp')
}

export function HookItem({ item }: { item: HookToDappMatch }) {
return (
<Item>
{item.dapp ? (
<Wrapper href={item.dapp.website} target="_blank">
<img src={item.dapp.image} alt={item.dapp.name} />
<styledEl.HookItemWrapper as="li">
<styledEl.HookItemHeader onClick={() => setIsOpen(!isOpen)}>
<styledEl.HookItemInfo>
<styledEl.HookNumber>{index + 1}</styledEl.HookNumber>
{item.dapp ? (
<>
<img src={item.dapp.image} alt={item.dapp.name} />
<span>{item.dapp.name}</span>
</>
) : (
<span>Unknown hook dapp</span>
)}
</styledEl.HookItemInfo>
<styledEl.ToggleIcon isOpen={isOpen}>
{isOpen ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
</styledEl.ToggleIcon>
</styledEl.HookItemHeader>
{isOpen && (
<styledEl.HookItemContent>
{item.dapp && (
<>
<p>
<b>Description:</b> {item.dapp.descriptionShort}
</p>
<p>
<b>Version:</b> {item.dapp.version}
</p>
<p>
<b>Website:</b>{' '}
<a href={item.dapp.website} target="_blank" rel="noopener noreferrer" onClick={handleLinkClick}>
{item.dapp.website}
</a>
</p>
</>
)}
<p>
<b>calldata:</b> {item.hook.callData}
</p>
<p>
<b>target:</b> {item.hook.target}
</p>
<p>
<strong>{item.dapp.name}</strong> <span>({item.dapp.version})</span>
<b>gasLimit:</b> {item.hook.gasLimit}
</p>
</Wrapper>
) : (
<div>Unknown hook dapp</div>
</styledEl.HookItemContent>
)}
</Item>
</styledEl.HookItemWrapper>
)
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,148 @@
import { UI } from '@cowprotocol/ui'

import styled from 'styled-components/macro'

export const Item = styled.li`
list-style: none;
margin: 0;
padding: 0;
export const HookItemWrapper = styled.li`
border: 1px solid var(${UI.COLOR_TEXT_OPACITY_10});
border-radius: 16px;
background: var(${UI.COLOR_PAPER_DARKER});
box-shadow: 0 5px 16px 0 transparent;
transition: all 0.2s ease-in-out;
overflow: hidden;
position: relative;
margin-bottom: 10px;
&:hover {
border: 1px solid var(${UI.COLOR_TEXT_OPACITY_50});
box-shadow: 0 5px 16px 0 var(${UI.COLOR_PRIMARY_OPACITY_25});
}
`

export const Wrapper = styled.a`
export const HookItemHeader = styled.div`
cursor: pointer;
display: flex;
flex-direction: row;
gap: 10px;
width: 100%;
justify-content: space-between;
align-items: center;
padding: 6px 10px 6px 5px;
font-size: 14px;
gap: 8px;
font-weight: 600;
color: var(${UI.COLOR_TEXT_OPACITY_70});
background: var(${UI.COLOR_PAPER});
border-top-left-radius: 16px;
border-top-right-radius: 16px;
transition: all 0.2s ease-in-out;
`

export const HookItemInfo = styled.div`
display: flex;
flex-flow: row nowrap;
align-items: center;
gap: 8px;
position: relative;
width: 100%;
user-select: none;
> img {
width: 30px;
height: 30px;
--size: 26px;
width: var(--size);
height: var(--size);
object-fit: contain;
border-radius: 9px;
background-color: var(${UI.COLOR_PAPER_DARKER});
padding: 2px;
}
> span {
font-weight: 500;
}
`

export const HookNumber = styled.i`
--minSize: 26px;
min-height: var(--minSize);
min-width: var(--minSize);
border-radius: 9px;
margin: 0;
padding: 3px 6px;
color: var(${UI.COLOR_TEXT});
font-weight: 500;
background: var(${UI.COLOR_PAPER_DARKER});
border: 1px dotted transparent;
font-style: normal;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease-in-out;
`

export const HookItemContent = styled.div`
padding: 10px;
font-size: 13px;
color: var(${UI.COLOR_TEXT_OPACITY_70});
margin: 10px 0 0;
> p {
margin: 0 0 1rem;
word-break: break-all;
font-weight: var(${UI.FONT_WEIGHT_NORMAL});
&:last-child {
margin: 0;
}
}
> p > b {
color: var(${UI.COLOR_TEXT});
display: block;
margin: 0 0 0.25rem;
text-transform: capitalize;
}
> p > a {
color: var(${UI.COLOR_TEXT_OPACITY_70});
text-decoration: underline;
&:hover {
color: var(${UI.COLOR_TEXT});
}
}
`

export const ToggleButton = styled.div<{ isOpen: boolean }>`
cursor: pointer;
display: flex;
align-items: center;
justify-content: flex-end;
opacity: ${({ isOpen }) => (isOpen ? 1 : 0.7)};
transition: opacity ${UI.ANIMATION_DURATION_SLOW} ease-in-out;
outline: none;
&:hover {
opacity: 1;
}
`

export const ToggleIcon = styled.div<{ isOpen: boolean }>`
--size: 16px;
transform: ${({ isOpen }) => (isOpen ? 'rotate(180deg)' : 'rotate(0deg)')};
transition: transform var(${UI.ANIMATION_DURATION_SLOW}) ease-in-out;
display: flex;
align-items: center;
justify-content: center;
width: var(--size);
height: var(--size);
> svg {
width: var(--size);
height: var(--size);
object-fit: contain;
path {
fill: var(${UI.COLOR_TEXT});
}
}
`
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import { ReactElement, useMemo, useState } from 'react'

import { latest } from '@cowprotocol/app-data'
import { HookToDappMatch, matchHooksToDappsRegistry } from '@cowprotocol/hook-dapp-lib'
import { InfoTooltip } from '@cowprotocol/ui'

import { ChevronDown, ChevronUp } from 'react-feather'

import { AppDataInfo, decodeAppData } from 'modules/appData'
import { useCustomHookDapps } from 'modules/hooksStore'

import { HookItem } from './HookItem'
import { HooksList, InfoWrapper, ToggleButton, Wrapper } from './styled'
import * as styledEl from './styled'
import { CircleCount } from './styled'

interface OrderHooksDetailsProps {
appData: string | AppDataInfo
Expand All @@ -20,37 +23,50 @@ export function OrderHooksDetails({ appData, children }: OrderHooksDetailsProps)
const appDataDoc = useMemo(() => {
return typeof appData === 'string' ? decodeAppData(appData) : appData.doc
}, [appData])
const preCustomHookDapps = useCustomHookDapps(true)
const postCustomHookDapps = useCustomHookDapps(false)

if (!appDataDoc) return null

const metadata = appDataDoc.metadata as latest.Metadata

const preHooksToDapp = matchHooksToDappsRegistry(metadata.hooks?.pre || [])
const postHooksToDapp = matchHooksToDappsRegistry(metadata.hooks?.post || [])
const preHooksToDapp = matchHooksToDappsRegistry(metadata.hooks?.pre || [], preCustomHookDapps)
const postHooksToDapp = matchHooksToDappsRegistry(metadata.hooks?.post || [], postCustomHookDapps)

if (!preHooksToDapp.length && !postHooksToDapp.length) return null

return children(
isOpen ? (
<Wrapper>
<ToggleButton onClick={() => setOpen(false)}>
<ChevronUp />
</ToggleButton>
<HooksInfo data={preHooksToDapp} title="Pre Hooks" />
<HooksInfo data={postHooksToDapp} title="Post Hooks" />
</Wrapper>
) : (
<Wrapper>
<span>
{preHooksToDapp.length ? `Pre: ${preHooksToDapp.length}` : ''}
{preHooksToDapp.length && postHooksToDapp.length ? ' | ' : ''}
{postHooksToDapp.length ? `Post: ${postHooksToDapp.length}` : ''}
</span>
<ToggleButton onClick={() => setOpen(true)}>
<ChevronDown />
</ToggleButton>
</Wrapper>
),
<styledEl.Wrapper isOpen={isOpen}>
<styledEl.Summary>
<styledEl.Label>
Hooks
<InfoTooltip content="Hooks are interactions before/after order execution." />
</styledEl.Label>
<styledEl.Content onClick={() => setOpen(!isOpen)}>
{preHooksToDapp.length > 0 && (
<styledEl.HookTag addSeparator={postHooksToDapp.length > 0}>
PRE <b>{preHooksToDapp.length}</b>
</styledEl.HookTag>
)}
{postHooksToDapp.length > 0 && (
<styledEl.HookTag isPost>
POST <b>{postHooksToDapp.length}</b>
</styledEl.HookTag>
)}
</styledEl.Content>
<styledEl.ToggleButton isOpen={isOpen} onClick={() => setOpen(!isOpen)}>
<styledEl.ToggleIcon isOpen={isOpen}>
{isOpen ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
</styledEl.ToggleIcon>
</styledEl.ToggleButton>
</styledEl.Summary>
{isOpen && (
<styledEl.Details>
<HooksInfo data={preHooksToDapp} title="Pre Hooks" />
<HooksInfo data={postHooksToDapp} title="Post Hooks" />
</styledEl.Details>
)}
</styledEl.Wrapper>,
)
}

Expand All @@ -63,14 +79,16 @@ function HooksInfo({ data, title }: HooksInfoProps) {
return (
<>
{data.length ? (
<InfoWrapper>
<h3>{title}</h3>
<HooksList>
{data.map((item) => {
return <HookItem key={item.hook.callData + item.hook.target + item.hook.gasLimit} item={item} />
})}
</HooksList>
</InfoWrapper>
<styledEl.InfoWrapper>
<h3>
{title} <CircleCount>{data.length}</CircleCount>
</h3>
<styledEl.HooksList>
{data.map((item, index) => (
<HookItem key={item.hook.callData + item.hook.target + item.hook.gasLimit} item={item} index={index} />
))}
</styledEl.HooksList>
</styledEl.InfoWrapper>
) : null}
</>
)
Expand Down
Loading

0 comments on commit 83184d2

Please sign in to comment.