Skip to content

Commit

Permalink
feat: refactor the interactive demo section on the landing page + mis…
Browse files Browse the repository at this point in the history
…c. styling updates (#1482)
  • Loading branch information
mindapivessa authored Oct 24, 2024
1 parent 30c7ad4 commit d1a948d
Show file tree
Hide file tree
Showing 15 changed files with 871 additions and 530 deletions.
1 change: 0 additions & 1 deletion site/docs/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { type ReactNode, useEffect, useState } from 'react';
import { http, WagmiProvider, createConfig } from 'wagmi';
import { base, baseSepolia } from 'wagmi/chains';
import { coinbaseWallet } from 'wagmi/connectors';

import '@coinbase/onchainkit/styles.css';

const queryClient = new QueryClient();
Expand Down
25 changes: 25 additions & 0 deletions site/docs/components/landing/CheckoutDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Checkout, CheckoutButton } from '@coinbase/onchainkit/checkout';
import App from '../App.tsx';

export const checkoutDemoCode = `
import {
Checkout,
CheckoutButton
} from '@coinbase/onchainkit/checkout';

<Checkout productId='my-product-id' >
<CheckoutButton coinbaseBranded={true}/>
</Checkout>
`;

function CheckoutDemo() {
return (
<App>
<Checkout productId="my-product-id">
<CheckoutButton coinbaseBranded={true} className="w-[180px]" />
</Checkout>
</App>
);
}

export default CheckoutDemo;
240 changes: 240 additions & 0 deletions site/docs/components/landing/ComponentPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import { useEffect, useState } from 'react';
import CopyIcon from '../svg/CopySvg.tsx';
import CheckIcon from '../svg/checkSvg.tsx';

// Demo components and code snippets
import CheckoutDemo, { checkoutDemoCode } from './CheckoutDemo.tsx';
import FundDemo, { fundDemoCode } from './FundDemo.tsx';
import IdentityDemo, { identityDemoCode } from './IdentityDemo.tsx';
import SwapDemo, { swapDemoCode } from './SwapDemo.tsx';
import TransactionDemo, { transactionDemoCode } from './TransactionDemo.tsx';
import WalletDemo, { walletDemoCode } from './WalletDemo.tsx';

type Component = {
name: string;
component: React.ComponentType;
code: string;
description: string;
};

const components: Component[] = [
{
name: 'Wallet',
component: WalletDemo,
code: walletDemoCode,
description: 'Enable users to onboard and log into your app with a wallet.',
},
{
name: 'Swap',
component: SwapDemo,
code: swapDemoCode,
description: 'Enable swaps between different cryptocurrencies.',
},
{
name: 'Checkout',
component: CheckoutDemo,
code: checkoutDemoCode,
description:
'Accept USDC payments with instant user onboarding and onramps.',
},
{
name: 'Transaction',
component: TransactionDemo,
code: transactionDemoCode,
description: 'Trigger onchain transactions and sponsor them with Paymaster',
},
{
name: 'Fund',
component: FundDemo,
code: fundDemoCode,
description: 'Fund wallets with a debit card or a coinbase account.',
},
{
name: 'Identity',
component: IdentityDemo,
code: identityDemoCode,
description:
'Display the Basename, avatar, and address associated with a wallet.',
},
];

function ComponentPreview() {
const [isClient, setIsClient] = useState(false);
const [copiedIndex, setCopiedIndex] = useState<number | null>(null);
const [activeTab, setActiveTab] = useState(0);
const [activeSubTab, setActiveSubTab] = useState<'preview' | 'code'>(
'preview',
);

useEffect(() => {
setIsClient(true);
}, []);

const copyToClipboard = (text: string, index: number) => {
navigator.clipboard.writeText(text).then(() => {
setCopiedIndex(index);
setTimeout(() => setCopiedIndex(null), 600);
});
};

if (!isClient) {
return <div>Loading...</div>;
}

return (
<div className="mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="flex flex-col gap-8 lg:flex-row lg:items-start">
<ComponentList
activeTab={activeTab}
setActiveTab={setActiveTab}
components={components}
/>
<PreviewContainer
activeTab={activeTab}
activeSubTab={activeSubTab}
setActiveSubTab={setActiveSubTab}
copiedIndex={copiedIndex}
copyToClipboard={copyToClipboard}
/>
</div>
</div>
);
}

interface ComponentListProps {
activeTab: number;
setActiveTab: (index: number) => void;
components: Component[];
}

function ComponentList({
activeTab,
setActiveTab,
components,
}: ComponentListProps) {
return (
<div className="w-full md:w-[300px] lg:flex-shrink-0">
<h3 className="pb-4 font-medium text-3xl text-zinc-900 dark:text-zinc-100">
Ready-to-use components
</h3>
<div className="pb-6 text-lg text-zinc-700 dark:text-zinc-500">
Accelerate your time-to-market with prebuilt components.
</div>
<div className="flex flex-col">
{components.map((comp, index) => (
<div key={comp.name} className="mb-4">
<button
type="button"
className={`w-full px-3 py-2 text-left text-base lg:text-lg ${
activeTab === index
? 'rounded-lg bg-zinc-100 font-semibold text-indigo-600 dark:bg-[#0F0F0F] dark:text-indigo-400'
: 'text-zinc-700 hover:rounded-lg hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-[#0F0F0F]'
}`}
onClick={() => setActiveTab(index)}
>
{comp.name}
{activeTab === index && (
<div className="mt-1 font-normal text-sm text-zinc-600 dark:text-zinc-400">
{comp.description}
</div>
)}
</button>
</div>
))}
</div>
</div>
);
}

type PreviewContainerProps = {
activeTab: number;
activeSubTab: 'preview' | 'code';
setActiveSubTab: (subTab: 'preview' | 'code') => void;
copiedIndex: number | null;
copyToClipboard: (text: string, index: number) => void;
};

function PreviewContainer({
activeTab,
activeSubTab,
setActiveSubTab,
copiedIndex,
copyToClipboard,
}: PreviewContainerProps) {
const ActiveComponent = components[activeTab].component;

return (
<div className="w-full flex-shrink-0 lg:w-[640px] xl:w-[720px]">
<div className="rounded-lg border border-zinc-200 dark:border-zinc-900">
<div className="relative w-full overflow-hidden rounded-lg bg-zinc-100 dark:bg-[#0F0F0F]">
<div className="flex items-center justify-between border-zinc-200 border-b dark:border-zinc-900">
<div className="flex">
<button
type="button"
className={`mt-2 ml-2 px-4 py-2 text-sm ${
activeSubTab === 'preview'
? 'border-indigo-600 border-b-2 bg-zinc-100 text-zinc-950 dark:border-indigo-400 dark:bg-[#0F0F0F] dark:text-zinc-50'
: 'text-zinc-700 dark:text-zinc-300'
}`}
onClick={() => setActiveSubTab('preview')}
>
Preview
</button>
<button
type="button"
className={`mt-2 px-4 py-2 text-sm ${
activeSubTab === 'code'
? 'border-indigo-600 border-b-2 text-zinc-950 dark:border-indigo-400 dark:text-zinc-50'
: 'text-zinc-700 dark:text-zinc-300'
}`}
onClick={() => setActiveSubTab('code')}
>
Code
</button>
</div>
{activeSubTab === 'code' && (
<button
type="button"
className="mr-2 rounded-md p-2 hover:bg-zinc-200 dark:hover:bg-zinc-800"
onClick={() =>
copyToClipboard(components[activeTab].code, activeTab)
}
title={
copiedIndex === activeTab ? 'Copied!' : 'Copy to clipboard'
}
>
{copiedIndex === activeTab ? (
<CheckIcon className="h-5 w-5 text-green-500 dark:text-green-400" />
) : (
<CopyIcon className="h-5 w-5 text-zinc-700 dark:text-zinc-300" />
)}
</button>
)}
</div>
<div className="h-[500px] overflow-auto">
<div
className={`${
activeSubTab === 'preview' ? 'flex' : 'hidden'
} h-full w-full items-center justify-center p-4`}
>
<div className="flex w-full max-w-[360px] items-center justify-center lg:max-w-none">
<ActiveComponent />
</div>
</div>
<div
className={`${
activeSubTab === 'code' ? 'block' : 'hidden'
} h-full w-full p-4`}
>
<pre className="h-full w-full overflow-auto bg-zinc-100 text-sm dark:bg-[#0F0F0F]">
<code>{components[activeTab].code}</code>
</pre>
</div>
</div>
</div>
</div>
</div>
);
}

export default ComponentPreview;
33 changes: 33 additions & 0 deletions site/docs/components/landing/FundDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { FundButton } from '@coinbase/onchainkit/fund';
import App from '../App.tsx';

export const fundDemoCode = `
import {
FundButton,
getOnrampBuyUrl
} from '@coinbase/onchainkit/fund';
import { useAccount } from 'wagmi';
const projectId = 'YOUR_CDP_PROJECT_ID';
const { address } = useAccount();
const onrampBuyUrl = getOnrampBuyUrl({
projectId,
addresses: { address: ['base'] },
assets: ['USDC'],
presetFiatAmount: 20,
fiatCurrency: 'USD'
});
<FundButton fundingUrl={onrampBuyUrl} />
`;

function FundDemo() {
return (
<App>
<FundButton className="w-[180px]" />
</App>
);
}

export default FundDemo;
49 changes: 49 additions & 0 deletions site/docs/components/landing/IdentityDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
Address,
Avatar,
Badge,
Identity,
Name,
} from '@coinbase/onchainkit/identity';
import App from '../App.tsx';

export const identityDemoCode = `
import {
Avatar,
Identity,
Name,
Badge,
Address
} from '@coinbase/onchainkit/identity';

<Identity
address="0x838aD0EAE54F99F1926dA7C3b6bFbF617389B4D9"
schemaId="0xf8b05c79f090979bf4a80270aba232dff11a10d9ca55c4f88de95317970f0de9"
>
<Avatar />
<Name>
<Badge />
</Name>
<Address />
</Identity>
`;

function IdentityDemo() {
return (
<App>
<Identity
schemaId="0xf8b05c79f090979bf4a80270aba232dff11a10d9ca55c4f88de95317970f0de9"
address="0x838aD0EAE54F99F1926dA7C3b6bFbF617389B4D9"
className="rounded-lg bg-gray-100dark:bg-gray-900 px-4 py-2"
>
<Avatar>
<Badge className="badge" />
</Avatar>
<Name />
<Address />
</Identity>
</App>
);
}

export default IdentityDemo;
Loading

0 comments on commit d1a948d

Please sign in to comment.