-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
302 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { useState } from "react"; | ||
import Image from "next/image"; | ||
import { usePlausible } from "next-plausible"; | ||
import CopyToClipboard from "react-copy-to-clipboard"; | ||
import { CheckCircleIcon, DocumentDuplicateIcon } from "@heroicons/react/24/outline"; | ||
import { Address } from "~~/components/scaffold-eth"; | ||
|
||
type Extension = { | ||
name: string; | ||
description: string; | ||
github: string; | ||
installCommand: string; | ||
builder: string; | ||
coBuilders: string[]; | ||
youtube?: string; | ||
}; | ||
|
||
export const ExtensionCard = ({ extension, isCurated }: { extension: Extension; isCurated: boolean }) => { | ||
const [commandCopied, setCommandCopied] = useState(false); | ||
const plausible = usePlausible(); | ||
|
||
const handleInstallClick = () => { | ||
setCommandCopied(true); | ||
setTimeout(() => { | ||
setCommandCopied(false); | ||
}, 800); | ||
|
||
const githubRepo = isCurated | ||
? `Curated/${extension.name}` | ||
: extension.github.split("github.com/")[1] || extension.github; | ||
|
||
// Track the click event with GitHub repo as a prop | ||
plausible("extensionCopyClick", { props: { id: githubRepo } }); | ||
}; | ||
|
||
return ( | ||
<div className="card bg-base-100 shadow-xl mb-8 flex flex-col mx-1"> | ||
<div className="card-body flex-grow"> | ||
<h2 className="card-title">{extension.name}</h2> | ||
<div className="flex justify-between items-start mb-2"> | ||
<div className="flex items-center gap-2"> | ||
{extension.github && ( | ||
<a href={extension.github} className="inline-block" target="_blank" rel="noopener noreferrer"> | ||
<Image src="/icon-github.svg" alt="github icon" width={24} height={24} /> | ||
</a> | ||
)} | ||
{extension.youtube && ( | ||
<a href={extension.youtube} className="inline-block" target="_blank" rel="noopener noreferrer"> | ||
<Image src="/icon-youtube.svg" alt="youtube icon" width={24} height={24} /> | ||
</a> | ||
)} | ||
</div> | ||
{isCurated ? ( | ||
<div className="badge badge-secondary p-3">Curated</div> | ||
) : ( | ||
<div> | ||
<Address address={extension.builder} disableAddressLink /> | ||
{extension.coBuilders && extension.coBuilders.length > 0 && ( | ||
<div className="text-sm mt-2"> | ||
{extension.coBuilders.map((coBuilder, index) => ( | ||
<Address key={index} address={coBuilder} disableAddressLink /> | ||
))} | ||
</div> | ||
)} | ||
</div> | ||
)} | ||
</div> | ||
<p | ||
className="overflow-hidden flex-grow" | ||
style={{ | ||
display: "-webkit-box", | ||
WebkitBoxOrient: "vertical", | ||
WebkitLineClamp: 5, | ||
maxHeight: "7.5em", | ||
}} | ||
> | ||
{extension.description} | ||
</p> | ||
{!isCurated && ( | ||
<div className="mt-2 text-sm text-yellow-600 bg-yellow-100 p-2 rounded"> | ||
⚠️ 3rd-party extension. Verify the source before installing. | ||
</div> | ||
)} | ||
</div> | ||
<div className="card-actions mx-4 p-4 pt-0 pb-6 mt-auto"> | ||
<CopyToClipboard text={extension.installCommand} onCopy={handleInstallClick}> | ||
<div className="flex items-center border-2 border-gray-300 rounded-xl px-3 sm:px-5 py-1 gap-2 cursor-pointer w-full"> | ||
<p className="m-0 text-center text-sm xl:text-base flex-grow">{extension.installCommand}</p> | ||
{commandCopied ? ( | ||
<CheckCircleIcon className="text-xl font-normal h-6 w-4 flex-shrink-0" aria-hidden="true" /> | ||
) : ( | ||
<DocumentDuplicateIcon className="text-xl font-normal h-6 w-4 flex-shrink-0" aria-hidden="true" /> | ||
)} | ||
</div> | ||
</CopyToClipboard> | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import { useState } from "react"; | ||
import Image from "next/image"; | ||
import Link from "next/link"; | ||
import type { GetStaticProps, NextPage } from "next"; | ||
import { MagnifyingGlassIcon } from "@heroicons/react/24/solid"; | ||
import { ExtensionCard } from "~~/components/ExtensionCard"; | ||
import { MetaHeader } from "~~/components/MetaHeader"; | ||
import curatedExtensions from "~~/public/extensions.json"; | ||
|
||
const BGAPP_API_URL = process.env.BGAPP_API_URL; | ||
|
||
type Extension = { | ||
name: string; | ||
description: string; | ||
github: string; | ||
installCommand: string; | ||
builder: string; | ||
coBuilders: string[]; | ||
youtube?: string; | ||
}; | ||
|
||
interface ExtensionsListProps { | ||
thirdPartyExtensions: Extension[]; | ||
} | ||
|
||
const ExtensionsList: NextPage<ExtensionsListProps> = ({ thirdPartyExtensions }) => { | ||
const [searchQuery, setSearchQuery] = useState(""); | ||
|
||
const allExtensions = [...curatedExtensions.curated, ...thirdPartyExtensions]; | ||
|
||
const filteredExtensions = allExtensions.filter(extension => { | ||
if (searchQuery.length < 3) return true; | ||
const lowerCaseSearch = searchQuery.toLowerCase(); | ||
return ( | ||
extension.name.toLowerCase().includes(lowerCaseSearch) || | ||
extension.description.toLowerCase().includes(lowerCaseSearch) | ||
); | ||
}); | ||
|
||
return ( | ||
<> | ||
<MetaHeader | ||
title="Extensions List | Scaffold-ETH 2" | ||
description="List of available extensions for Scaffold-ETH 2" | ||
/> | ||
<div className="container mx-auto p-4 min-h-screen flex flex-col -mb-16"> | ||
{/* Header section */} | ||
<div className="flex items-center justify-between mb-8"> | ||
<Link href="/" className="flex items-center gap-2"> | ||
<div className="flex relative w-8 sm:w-10 h-8 sm:h-10"> | ||
<Image alt="SE2 logo" className="cursor-pointer" fill src="/logo.svg" /> | ||
</div> | ||
<span className="text-xl sm:text-2xl font-medium">Scaffold-ETH 2</span> | ||
</Link> | ||
<Link href="/" className="btn btn-sm btn-ghost"> | ||
Back to Home | ||
</Link> | ||
</div> | ||
|
||
<div className="flex flex-col items-center justify-center gap-4 mb-4"> | ||
<h1 className="text-3xl md:text-4xl font-bold text-center">Extensions List</h1> | ||
<div className="relative w-full max-w-xs"> | ||
<input | ||
type="text" | ||
placeholder="Search extensions" | ||
className="input input-bordered w-full pr-10 text-sm md:text-base" | ||
onChange={e => setSearchQuery(e.target.value)} | ||
/> | ||
<MagnifyingGlassIcon className="absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 md:h-5 md:w-5 text-gray-400" /> | ||
</div> | ||
</div> | ||
<p className="text-base md:text-lg mb-8 text-center max-w-4xl mx-auto"> | ||
Explore our Curated (by BuidlGuidl) and community-contributed extensions for Scaffold-ETH 2.{" "} | ||
<br className="hidden md:inline"></br> To install an extension, simply copy and run the installation command | ||
provided for each extension. | ||
</p> | ||
|
||
{/* Combined extensions list */} | ||
<div className="flex-grow"> | ||
{filteredExtensions.length > 0 ? ( | ||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pb-16"> | ||
{filteredExtensions.map((extension, index) => ( | ||
<ExtensionCard | ||
key={index} | ||
extension={extension} | ||
isCurated={curatedExtensions.curated.includes(extension)} | ||
/> | ||
))} | ||
</div> | ||
) : ( | ||
<div className="flex items-center justify-center flex-grow"> | ||
<p className="text-center text-lg font-light">- No extensions found matching your search -</p> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
// get third party extensions from buidlguidl app (builds with "extension" type) | ||
export const getStaticProps: GetStaticProps<ExtensionsListProps> = async () => { | ||
try { | ||
if (!BGAPP_API_URL) { | ||
throw new Error("BGAPP_API_URL environment variable is not set"); | ||
} | ||
|
||
const response = await fetch(`${BGAPP_API_URL}/builds?type=extension`); | ||
const data = await response.json(); | ||
const formattedExtensions = data.map((ext: any) => { | ||
const githubUrlParts = ext.branch.split("/"); | ||
const githubUsername = githubUrlParts[3]; | ||
const repoName = githubUrlParts[4]; | ||
|
||
return { | ||
name: ext.name, | ||
description: ext.desc, | ||
github: ext.branch, | ||
installCommand: `npx create-eth@latest -e ${githubUsername}/${repoName}`, | ||
builder: ext.builder, | ||
coBuilders: ext.coBuilders || [], | ||
youtube: ext.videoUrl || null, | ||
}; | ||
}); | ||
|
||
return { | ||
props: { | ||
thirdPartyExtensions: formattedExtensions, | ||
}, | ||
// Revalidate every 6 hours (21600 seconds) | ||
revalidate: 21600, | ||
}; | ||
} catch (error) { | ||
console.error("Error fetching third-party extensions:", error); | ||
return { | ||
props: { | ||
thirdPartyExtensions: [], | ||
}, | ||
revalidate: 21600, | ||
}; | ||
} | ||
}; | ||
|
||
export default ExtensionsList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{ | ||
"curated": [ | ||
{ | ||
"name": "subgraph", | ||
"description": "This Scaffold-ETH 2 extension helps you build and test subgraphs locally for your contracts. It also enables interaction with the front-end and facilitates easy deployment to Subgraph Studio.", | ||
"github": "https://github.com/scaffold-eth/create-eth-extensions/tree/subgraph", | ||
"installCommand": "npx create-eth@latest -e subgraph", | ||
"builder": "0x1A2d838c4bbd1e73d162d0777d142c1d783Cb831", | ||
"coBuilders": [] | ||
}, | ||
{ | ||
"name": "eip-712", | ||
"description": "An implementation of EIP-712, allowing you to send, sign, and verify typed messages in a user-friendly manner.", | ||
"github": "https://github.com/scaffold-eth/create-eth-extensions/tree/eip-712", | ||
"installCommand": "npx create-eth@latest -e eip-712", | ||
"builder": "0x1A2d838c4bbd1e73d162d0777d142c1d783Cb831", | ||
"coBuilders": [] | ||
}, | ||
{ | ||
"name": "ponder", | ||
"description": "This Scaffold-ETH 2 extension comes pre-configured with ponder.sh, providing an example to help you get started quickly.", | ||
"github": "https://github.com/scaffold-eth/create-eth-extensions/tree/ponder", | ||
"installCommand": "npx create-eth@latest -e ponder", | ||
"builder": "0x5dCb5f4F39Caa6Ca25380cfc42280330b49d3c93", | ||
"coBuilders": [] | ||
}, | ||
{ | ||
"name": "onchainkit", | ||
"description": "This Scaffold-ETH 2 extension comes pre-configured with onchainkit, providing an example to help you get started quickly.", | ||
"github": "https://github.com/scaffold-eth/create-eth-extensions/tree/onchainkit", | ||
"installCommand": "npx create-eth@latest -e onchainkit", | ||
"builder": "0x45334F41aAA464528CD5bc0F582acadC49Eb0Cd1", | ||
"coBuilders": [] | ||
}, | ||
{ | ||
"name": "erc-20", | ||
"description": "This extension introduces an ERC-20 token contract and demonstrates how to interact with it, including getting a holder balance and transferring tokens.", | ||
"github": "https://github.com/scaffold-eth/create-eth-extensions/tree/erc-20", | ||
"installCommand": "npx create-eth@latest -e erc-20", | ||
"builder": "0x5dCb5f4F39Caa6Ca25380cfc42280330b49d3c93", | ||
"coBuilders": ["0x60583563D5879C2E59973E5718c7DE2147971807"] | ||
} | ||
] | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.