Skip to content

Commit c9fd962

Browse files
authored
style: UI/UX updates (#22)
* style: header, logo, font, home page improvements * style: tweak white/black variants * fix: icons * chore: remove debug log from origin opcode * style: initial updates * feat: copyable links for section headers * feat: copyable diff content * style: color tweaks
1 parent 1ca9ba9 commit c9fd962

16 files changed

+234
-75
lines changed

public/logo.svg

Lines changed: 63 additions & 23 deletions
Loading

src/chains/arbitrum/vm/opcodes/environment/origin.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { origin as baseOpcode } from '@/chains/optimism/vm/opcodes/environment/o
22
import { Opcode } from '@/types';
33

44
const { references: _references, ...opcode } = baseOpcode;
5-
const o: Omit<Opcode, 'supportedHardforks'> = {
5+
export const origin: Omit<Opcode, 'supportedHardforks'> = {
66
...opcode,
77
references: [
88
{
@@ -15,5 +15,3 @@ const o: Omit<Opcode, 'supportedHardforks'> = {
1515
},
1616
],
1717
};
18-
console.log('origin:', o);
19-
export const origin = o;

src/components/diff/DiffMetadata.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Chain as Metadata } from '@wagmi/chains';
22
import { getAddress } from 'viem';
3+
import { Copyable } from '@/components/ui/Copyable';
34
import { classNames, toUppercase } from '@/lib/utils';
45
import { ExternalLink } from '../layout/ExternalLink';
56

@@ -28,13 +29,13 @@ const formatRpcUrls = (data: Metadata['rpcUrls']) => {
2829
<ul>
2930
{rpcUrls.http.map((url) => (
3031
<li className='text-secondary text-sm' key={url}>
31-
{url}
32+
<Copyable content={url} />
3233
</li>
3334
))}
3435
{rpcUrls.webSocket &&
3536
rpcUrls.webSocket.map((url) => (
3637
<li className='text-secondary text-sm' key={url}>
37-
{url}
38+
<Copyable content={url} />
3839
</li>
3940
))}
4041
</ul>
@@ -44,7 +45,7 @@ const formatRpcUrls = (data: Metadata['rpcUrls']) => {
4445
<div>
4546
{Object.entries(data).map(([key, rpcUrls], index) => (
4647
<div key={key}>
47-
<h3 className={classNames('font-bold', index > 0 && 'mt-2')}>{toUppercase(key)}</h3>
48+
<h3 className={classNames('font-bold', index > 0 && 'mt-6')}>{toUppercase(key)}</h3>
4849
{renderRpcUrls(rpcUrls)}
4950
</div>
5051
))}
@@ -58,7 +59,7 @@ const formatBlockExplorerUrls = (data: Metadata['blockExplorers']) => {
5859
<div>
5960
{Object.entries(data).map(([key, blockExplorer], index) => (
6061
<div key={key}>
61-
<h3 className={classNames('font-bold', index > 0 && 'mt-2')}>{toUppercase(key)}</h3>
62+
<h3 className={classNames('font-bold', index > 0 && 'mt-6')}>{toUppercase(key)}</h3>
6263
<p className='text-secondary text-sm'>
6364
<ExternalLink href={blockExplorer.url} text={blockExplorer.url} />
6465
</p>
@@ -69,8 +70,8 @@ const formatBlockExplorerUrls = (data: Metadata['blockExplorers']) => {
6970
};
7071

7172
const formatFieldInfo = (field: MetadataKey, contents: Metadata[MetadataKey]) => {
72-
if (field === 'id') return contents?.toString();
73-
if (field === 'name') return contents?.toString();
73+
if (field === 'id') return <Copyable content={contents?.toString() || ''} />;
74+
if (field === 'name') return <Copyable content={contents?.toString() || ''} />;
7475
if (field === 'rpcUrls') return formatRpcUrls(contents as Metadata['rpcUrls']);
7576
if (field === 'blockExplorers') {
7677
return formatBlockExplorerUrls(contents as Metadata['blockExplorers']);
@@ -107,11 +108,11 @@ export const DiffMetadata = ({ base, target, onlyShowDiff }: Props) => {
107108
showField && (
108109
<div
109110
key={field}
110-
className='flex items-center justify-between border-b border-zinc-500/10 py-1 dark:border-zinc-500/20'
111+
className='grid grid-cols-12 items-center border-b border-zinc-500/10 py-6 dark:border-zinc-500/20'
111112
>
112-
<div className='flex-1'>{formatFieldInfo(field, base[field])}</div>
113-
<div className='flex-1 text-center'>{formatFieldDisplayName(field)}</div>
114-
<div className='flex-1'>{formatFieldInfo(field, target[field])}</div>
113+
<div className='col-span-2'>{formatFieldDisplayName(field)}</div>
114+
<div className='col-span-5 pr-4'>{formatFieldInfo(field, base[field])}</div>
115+
<div className='col-span-5'>{formatFieldInfo(field, target[field])}</div>
115116
</div>
116117
)
117118
);

src/components/diff/DiffOpcodes.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Copyable } from '@/components/ui/Copyable';
12
import { CURRENT_MAINNET_HARDFORK } from '@/lib/constants';
23
import { opcodeId } from '@/lib/opcodes';
34
import { classNames, formatPrefixByte } from '@/lib/utils';
@@ -281,15 +282,14 @@ export const DiffOpcodes = ({ base, target, onlyShowDiff }: Props): JSX.Element
281282
showOpcode && (
282283
<div
283284
key={id}
284-
className='flex items-center justify-between border-b border-zinc-500/10 py-1 dark:border-zinc-500/20'
285+
className='grid grid-cols-12 items-center border-b border-zinc-500/10 py-6 dark:border-zinc-500/20'
285286
>
286-
<div className='flex-1'>{formatOpcode(baseOpcode)}</div>
287-
<p className='flex-1 text-center'>
288-
<span>
289-
{baseOpcode?.name} (#{baseOpcode?.number && formatPrefixByte(baseOpcode?.number)})
290-
</span>
291-
</p>
292-
<div className='flex-1'>{formatOpcode(targetOpcode)}</div>
287+
<div className='col-span-2'>
288+
<Copyable content={baseOpcode?.name.toLocaleUpperCase()} />
289+
<Copyable content={formatPrefixByte(baseOpcode?.number)} />
290+
</div>
291+
<div className='col-span-5 pr-4'>{formatOpcode(baseOpcode)}</div>
292+
<div className='col-span-5'>{formatOpcode(targetOpcode)}</div>
293293
</div>
294294
)
295295
);

src/components/diff/DiffPrecompiles.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Address, getAddress } from 'viem';
2+
import { Copyable } from '@/components/ui/Copyable';
23
import { Precompile, Predeploy } from '@/types';
34

45
type Props = {
@@ -43,11 +44,11 @@ export const DiffPrecompiles = ({ base, target, onlyShowDiff }: Props) => {
4344
showPrecompile && (
4445
<div
4546
key={addr}
46-
className='flex items-center justify-between border-b border-zinc-500/10 py-1 dark:border-zinc-500/20'
47+
className='grid grid-cols-12 items-center border-b border-zinc-500/10 py-6 dark:border-zinc-500/20'
4748
>
48-
<div className='flex-1'>{formatPrecompile(basePrecompile)}</div>
49-
<div className='flex-1 text-center'>{formatAddress(addr)}</div>
50-
<div className='flex-1'>{formatPrecompile(targetPrecompile)}</div>
49+
<Copyable className='col-span-2' content={formatAddress(addr)} textToCopy={addr} />
50+
<div className='col-span-5 pr-4'>{formatPrecompile(basePrecompile)}</div>
51+
<div className='col-span-5'>{formatPrecompile(targetPrecompile)}</div>
5152
</div>
5253
)
5354
);

src/components/diff/DiffSignatureTypes.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Copyable } from '@/components/ui/Copyable';
12
import { formatPrefixByte } from '@/lib/utils';
23
import { SignatureType } from '@/types';
34

@@ -35,11 +36,11 @@ export const DiffSignatureTypes = ({ base, target, onlyShowDiff }: Props) => {
3536
showSigType && (
3637
<div
3738
key={prefix}
38-
className='flex items-center justify-between border-b border-zinc-500/10 py-1 dark:border-zinc-500/20'
39+
className='grid grid-cols-12 items-center border-b border-zinc-500/10 py-6 dark:border-zinc-500/20'
3940
>
40-
<div className='flex-1'>{formatSigType(baseSigType)}</div>
41-
<div className='flex-1 text-center'>{formatPrefixByte(prefix)}</div>
42-
<div className='flex-1'>{formatSigType(targetSigType)}</div>
41+
<Copyable className='col-span-2' content={formatPrefixByte(prefix)} />
42+
<div className='col-span-5 pr-4'>{formatSigType(baseSigType)}</div>
43+
<div className='col-span-5'>{formatSigType(targetSigType)}</div>
4344
</div>
4445
)
4546
);

src/components/layout/Header.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ export const Header = () => {
1010
<div className='bg-yellow-500 py-2 text-center text-sm font-semibold dark:bg-yellow-600'>
1111
This site is a work in progress and should not yet be relied on! Check out{' '}
1212
<ExternalLink
13-
className='text-black underline dark:text-white'
13+
className='text-zinc-1000 underline dark:text-zinc-0'
1414
href='https://github.com/mds1/evm-diff'
1515
text='the repo'
1616
/>{' '}
1717
if you want to contribute.
1818
</div>
1919
<div>
20-
<div className='flex items-center justify-between px-4 py-6 sm:px-6 md:space-x-10'>
20+
<div className='flex items-center justify-between px-4 py-2 sm:px-6 sm:py-6 md:space-x-10'>
2121
<div>
2222
<Link href='/' className='flex'>
2323
<span className='sr-only'>{COMPANY_NAME}</span>
24-
<Image className='h-14' src={logo} alt='logo' />
24+
<Image className='h-8 sm:h-14' src={logo} alt='logo' />
2525
</Link>
2626
</div>
2727
</div>

src/components/layout/Layout.tsx

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,52 @@
1+
import { useRouter } from 'next/router';
12
import { Footer } from '@/components/layout/Footer';
23
import { Header } from '@/components/layout/Header';
4+
import { classNames } from '@/lib/utils';
35

46
interface Props {
57
children: JSX.Element;
68
}
79

810
export const Layout = ({ children }: Props) => {
11+
const { route } = useRouter();
12+
const isHome = route === '/';
13+
914
return (
10-
<div className='flex min-h-screen flex-col bg-gradient-to-br from-zinc-50 via-zinc-200 to-zinc-300 dark:from-zinc-800 dark:to-zinc-900'>
15+
<div className='relative isolate flex min-h-screen flex-col bg-zinc-50 dark:bg-zinc-900'>
1116
<Header />
1217
<main className='text-primary my-4 h-full w-full flex-1 px-4 sm:px-6 md:justify-between lg:px-8'>
1318
{children}
1419
</main>
1520
<Footer />
21+
<svg
22+
viewBox='0 0 1024 1024'
23+
className={classNames(
24+
'fixed left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-x-1/2',
25+
!isHome && 'opacity-0'
26+
)}
27+
aria-hidden='true'
28+
>
29+
<circle
30+
cx={512}
31+
cy={512}
32+
r={512}
33+
fill='url(#759c1415-0410-454c-8f7c-9a820de03641)'
34+
fillOpacity='0.2'
35+
/>
36+
<defs>
37+
<radialGradient
38+
id='759c1415-0410-454c-8f7c-9a820de03641'
39+
cx={0}
40+
cy={0}
41+
r={1}
42+
gradientUnits='userSpaceOnUse'
43+
gradientTransform='translate(512 512) rotate(90) scale(512)'
44+
>
45+
<stop stopColor='#10B981' />
46+
<stop offset={1} stopColor='#059669' stopOpacity={0} />
47+
</radialGradient>
48+
</defs>
49+
</svg>
1650
</div>
1751
);
1852
};

src/components/ui/ChainDiffSelectorChainCombobox.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const ChainDiffSelectorChainCombobox = ({ label, chains, value, onChange
5858
</Combobox.Button>
5959

6060
{filteredChains.length > 0 && (
61-
<Combobox.Options className='bg-primary absolute z-10 mt-1 max-h-56 w-full overflow-auto rounded-md py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm'>
61+
<Combobox.Options className='bg-primary absolute z-10 mt-1 max-h-56 w-full overflow-auto rounded-md py-1 text-base shadow-lg ring-1 ring-zinc-1000 ring-opacity-5 focus:outline-none sm:text-sm'>
6262
{filteredChains.map((chain) => (
6363
<Combobox.Option
6464
key={chain.metadata.id}

src/components/ui/Copyable.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { ClipboardDocumentIcon } from '@heroicons/react/24/outline';
2+
import { classNames, copyToClipboard } from '@/lib/utils';
3+
4+
// When content is a string, `textToCopy` is optional.
5+
interface ContentStringProps {
6+
content: string;
7+
textToCopy?: string;
8+
Icon?: typeof ClipboardDocumentIcon;
9+
className?: string;
10+
}
11+
12+
// When text is a JSX element, `textToCopy` is required.
13+
interface ContentElementProps {
14+
content: JSX.Element;
15+
textToCopy: string;
16+
Icon?: typeof ClipboardDocumentIcon;
17+
className?: string;
18+
}
19+
20+
export const Copyable = ({
21+
content,
22+
textToCopy,
23+
Icon = ClipboardDocumentIcon,
24+
className = '',
25+
}: ContentStringProps | ContentElementProps) => {
26+
const onCopy = (text: string) => {
27+
copyToClipboard(text);
28+
};
29+
30+
return (
31+
<div className={classNames('group group relative flex w-max items-center', className)}>
32+
<div className='relative flex w-full items-center'>
33+
{content}
34+
<Icon
35+
onClick={() => onCopy(String(textToCopy || content))}
36+
className='ml-2 h-4 cursor-pointer opacity-0 transition-opacity group-hover:opacity-100'
37+
/>
38+
</div>
39+
</div>
40+
);
41+
};

src/components/ui/Toggle.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ export const Toggle = ({ enabled, setEnabled, label }: Props) => {
2222
aria-hidden='true'
2323
className={classNames(
2424
enabled ? 'translate-x-5' : 'translate-x-0',
25-
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out'
25+
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-zinc-0 shadow ring-0 transition duration-200 ease-in-out'
2626
)}
2727
/>
2828
</Switch>
2929
<Switch.Label as='span' className='ml-3 text-sm'>
30-
<span className='text-gray-500'>{label}</span>
30+
<span className='text-secondary'>{label}</span>
3131
</Switch.Label>
3232
</Switch.Group>
3333
);

src/lib/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ import { pad } from 'viem';
33
// Takes an arbitrary number of class names, filtering out any falsey values.
44
export const classNames = (...classes: (string | boolean)[]) => classes.filter(Boolean).join(' ');
55

6+
// Copies the provided text to the clipboard
7+
export const copyToClipboard = (text: string) => {
8+
navigator.clipboard.writeText(text).then(
9+
() => console.log('Copying to clipboard was successful!'),
10+
(err) => console.error('Could not copy text to clipboard: ', err)
11+
);
12+
};
13+
614
// Given a `record` (i.e. an object), return an array of its values sorted by the given `field`.
715
// Make sure the field is a number or string or the sort behavior based on `>` and `<` may be
816
// undefined.

0 commit comments

Comments
 (0)