Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions src/components/Codeblock/Codeblock.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { Meta, StoryObj } from "@storybook/nextjs"

import Codeblock from "."

const meta = {
title: "Components / Content / Codeblock",
component: Codeblock,
parameters: {
chromatic: { disableSnapshot: true },
docs: {
description: {
component:
"Syntax-highlighted code block built on `prism-react-renderer`. Renders a line-numbered listing, with optional Copy and Show all / Show less controls. Languages with copy-button support: `js`, `json`, `python`, `solidity`. `bash` blocks suppress line numbers. Pass `fromHomepage` to render without the top bar (no copy, no collapse).",
},
},
},
decorators: [
(Story) => (
<div className="max-w-3xl">
<Story />
</div>
),
],
} satisfies Meta<typeof Codeblock>

export default meta

type Story = StoryObj<typeof meta>

const solidityExample = `// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Counter {
uint256 public count;

function increment() external {
count += 1;
}

function reset() external {
count = 0;
}
}`

const jsExample = `import { createPublicClient, http } from "viem"
import { mainnet } from "viem/chains"

const client = createPublicClient({
chain: mainnet,
transport: http(),
})

const block = await client.getBlock()
console.log(block.number)`

const pythonExample = `from web3 import Web3

w3 = Web3(Web3.HTTPProvider("https://mainnet.example/v3/KEY"))

latest = w3.eth.get_block("latest")
print(latest.number)`

const bashExample = `pnpm install
pnpm dev`

export const Default: Story = {
args: {
codeLanguage: "language-solidity",
children: solidityExample,
},
}

export const JavaScript: Story = {
args: {
codeLanguage: "language-js",
children: jsExample,
},
}

export const Python: Story = {
args: {
codeLanguage: "language-python",
children: pythonExample,
},
}

export const Bash: Story = {
args: {
codeLanguage: "language-bash",
children: bashExample,
},
}

export const Collapsible: Story = {
args: {
codeLanguage: "language-solidity",
allowCollapse: true,
children: Array.from(
{ length: 40 },
(_, i) => ` uint256 line${i} = ${i};`
).join("\n"),
},
}

export const NoCollapse: Story = {
args: {
codeLanguage: "language-solidity",
allowCollapse: false,
children: solidityExample,
},
}

export const FromHomepage: Story = {
args: {
codeLanguage: "language-solidity",
fromHomepage: true,
children: solidityExample,
},
}
File renamed without changes.
77 changes: 77 additions & 0 deletions src/components/CopyToClipboard/CopyToClipboard.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Check, Clipboard } from "lucide-react"
import { Meta, StoryObj } from "@storybook/nextjs"

import { VStack } from "@/components/ui/flex"

import CopyToClipboard, { CopyButton } from "."

const meta = {
title: "Components / Content / CopyToClipboard",
component: CopyToClipboard,
parameters: {
chromatic: { disableSnapshot: true },
docs: {
description: {
component:
'Bare clipboard trigger that uses the render-prop pattern: pass a function child that receives `isCopied: boolean` and returns the label / icon for each state. Use `inline` to render as `<button class="inline">` for use inside running prose. The named export `CopyButton` is a pre-styled icon-only variant for compact UIs.',
},
},
},
decorators: [
(Story) => (
<div className="max-w-md">
<Story />
</div>
),
],
} satisfies Meta<typeof CopyToClipboard>

export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {
args: {
text: "0x742d35Cc6634C0532925a3b844Bc9e7595f7E0d8",
children: (isCopied) =>
isCopied ? (
<span className="inline-flex items-center gap-2 text-success">
<Check className="size-4" /> Copied
</span>
) : (
<span className="inline-flex items-center gap-2 text-primary">
<Clipboard className="size-4" /> Copy address
</span>
),
},
}

export const Inline: Story = {
args: {
text: "Ethereum is a global, decentralized platform for money and new kinds of applications.",
inline: true,
children: (isCopied) => (
<span className="underline">{isCopied ? "Copied!" : "Copy quote"}</span>
),
},
}

export const TextLabel: Story = {
args: {
text: "ethereum.org",
children: (isCopied) => (
<span>{isCopied ? "Copied to clipboard" : "Copy link"}</span>
),
},
}

export const CopyButtonVariant = {
render: () => (
<VStack className="items-start gap-3">
<p className="text-sm text-body-medium">
The `CopyButton` named export -- icon-only, no render prop.
</p>
<CopyButton message="0x742d35Cc6634C0532925a3b844Bc9e7595f7E0d8" />
</VStack>
),
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import { Clipboard, ClipboardCheck } from "lucide-react"

import { cn } from "@/lib/utils/cn"
import { Button, type ButtonProps } from "@/components/ui/buttons/Button"

import { Button, type ButtonProps } from "./ui/buttons/Button"
import { cn } from "@/lib/utils/cn"

import { useClipboard } from "@/hooks/useClipboard"

Expand Down
126 changes: 126 additions & 0 deletions src/components/ProductList/ProductList.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { Meta, StoryObj } from "@storybook/nextjs"

import ProductList from "."

const meta = {
title: "Components / Content / ProductList",
component: ProductList,
parameters: {
chromatic: { disableSnapshot: true },
docs: {
description: {
component:
"Vertical list of product / tool entries used on directory pages (wallets, dapps, dev tools). Each row shows an optional 66x66 thumbnail, a title, a description, optional content items, and an optional outlined CTA labelled by `actionLabel`. Pass `category` to render a heading above the list. Items are visually separated by dividers between rows.",
},
},
},
decorators: [
(Story) => (
<div className="max-w-3xl">
<Story />
</div>
),
],
} satisfies Meta<typeof ProductList>

export default meta

type Story = StoryObj<typeof meta>

const sampleContent = [
{
title: "Uniswap",
description:
"A decentralized exchange protocol that lets users swap tokens without intermediaries.",
image: "/images/dapps/uni.png",
alt: "Uniswap logo",
link: "https://uniswap.org",
},
{
title: "Aave",
description:
"An open-source, non-custodial protocol for earning interest on deposits and borrowing assets.",
image: "/images/dapps/aave.png",
alt: "Aave logo",
link: "https://aave.com",
},
{
title: "Compound",
description:
"An algorithmic, autonomous interest rate protocol for lending and borrowing crypto assets.",
image: "/images/dapps/compound.png",
alt: "Compound logo",
link: "https://compound.finance",
},
]

export const Default: Story = {
args: {
actionLabel: "Visit",
content: sampleContent,
},
}

export const WithCategory: Story = {
args: {
actionLabel: "Visit",
category: "Decentralized exchanges",
content: sampleContent,
},
}

export const WithoutImages: Story = {
args: {
actionLabel: "Open",
content: sampleContent.map(({ title, description, link }) => ({
title,
description,
link,
})),
},
}

export const WithoutLinks: Story = {
args: {
actionLabel: "Visit",
content: sampleContent.map(({ title, description, image, alt }) => ({
title,
description,
image,
alt,
})),
},
}

export const WithContentItems: Story = {
args: {
actionLabel: "Visit",
category: "Lending markets",
content: [
{
title: "Morpho",
description:
"Permissionless lending markets with isolated risk and curated vaults.",
image: "/images/dapps/morpho.png",
alt: "Morpho logo",
link: "https://morpho.org",
contentItems: [
<span key="markets">Isolated markets</span>,
<span key="audited">Audited contracts</span>,
],
},
{
title: "Spark",
description:
"Borrow and save against blue-chip collateral on Ethereum mainnet.",
image: "/images/dapps/sparkfi.png",
alt: "Spark logo",
link: "https://spark.fi",
contentItems: [
<span key="rates">Predictable savings rates</span>,
<span key="dai">Backed by the DAI stablecoin</span>,
],
},
],
},
}
File renamed without changes.
Loading