diff --git a/blog/03-28-2023-introducing-prosperity-passport/building-a-conversational-ai-agent-for-celo-transactions-with-goat.md b/blog/03-28-2023-introducing-prosperity-passport/building-a-conversational-ai-agent-for-celo-transactions-with-goat.md new file mode 100644 index 0000000000..6605dd9c2c --- /dev/null +++ b/blog/03-28-2023-introducing-prosperity-passport/building-a-conversational-ai-agent-for-celo-transactions-with-goat.md @@ -0,0 +1,306 @@ +--- +title: Building a Conversational AI Agent for Celo Transactions with GOAT +description: This tutorial guides you through creating a Node.js application using TypeScript that leverages the GOAT AI agent framework to interact with the Celo blockchain. + +authors: + - name: Viral Sangani + title: DevRel, Celo Foundation + url: https://github.com/viral-sangani + image_url: https://avatars.githubusercontent.com/u/36530381?v=4 +tags: ["beginner", "ai", "celo"] +hide_table_of_contents: false +slug: /tutorials/building-a-conversational-ai-agent-for-celo-transactions-with-goat +--- + +## 🌱 Introduction + +This tutorial guides you through creating a Node.js application using TypeScript that leverages the GOAT AI agent framework to interact with the Celo blockchain. GOAT allows you to use natural language prompts to perform on-chain actions, such as transferring tokens and checking allowances. We'll cover setup, configuration, code explanation, and common usage scenarios. + +## Prerequisites + +Before you begin, ensure you have the following: + +- **Node.js (v16 or higher) and npm (or yarn) installed.** You can download Node.js from [https://nodejs.org/](https://nodejs.org/). +- **A Celo wallet with a private key.** You'll need a wallet with some CELO and cUSD for testing. _Never commit your private key to version control._ +- **An RPC provider URL for the Celo network.** We'll use [Forno](https://forno.celo.org/) in this example, which is a public provider. For production, consider using a dedicated RPC provider like [Ankr](https://www.ankr.com/), [QuickNode](https://www.quicknode.com/), or others. +- **An OpenAI API key.** GOAT utilizes OpenAI's language models. Obtain an API key from [https://platform.openai.com/](https://platform.openai.com/). +- **A code editor or IDE.** VS Code, Sublime Text, or any other code editor will work. + +## Project Setup + +1. **Create a new project directory:** + + ```bash + mkdir goat-celo-tutorial + cd goat-celo-tutorial + ``` + +2. **Initialize a Node.js project:** + + ```bash + npm init -y + ``` + +3. **Install dependencies:** + + ```bash + npm install typescript @ai-sdk/openai @goat-sdk/adapter-vercel-ai @goat-sdk/plugin-erc20 @goat-sdk/wallet-viem ai dotenv viem @types/node + ``` + + - `typescript`: For using TypeScript. + - `@ai-sdk/openai`: The OpenAI adapter for AI-SDK. + - `@goat-sdk/adapter-vercel-ai`: GOAT's adapter for using AI-SDK. + - `@goat-sdk/plugin-erc20`: GOAT plugin for interacting with ERC-20 tokens. + - `@goat-sdk/wallet-viem`: GOAT's wallet integration using Viem. + - `ai`: The core AI-SDK library. + - `dotenv`: For loading environment variables from a `.env` file. + - `viem`: A lightweight Ethereum library for interacting with the blockchain. + - `@types/node`: TypeScript definitions for Node.js. + +4. **Initialize TypeScript configuration:** + + ```bash + npx tsc --init + ``` + +5. **Configure `tsconfig.json`:** + + Open `tsconfig.json` and update it with the following settings (adjusting paths as needed): + + ```json + { + "compilerOptions": { + "target": "ES2020", // Or a later version if supported by your environment + "module": "commonjs", + "lib": ["ESNext"], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", // Output directory for compiled JavaScript + "rootDir": "./src", // Source directory for TypeScript files + "moduleResolution": "node", + "resolveJsonModule": true, + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] + } + ``` + + - `outDir`: Specifies where the compiled JavaScript files will be placed. + - `rootDir`: Specifies the root directory for your TypeScript source files. + - `sourceMap`: Enables source map generation, helpful for debugging. + - `resolveJsonModule`: allows importing JSON files + - `moduleResolution`: Specifies how modules are resolved. "node" is standard for Node.js projects. + +## Project Structure + +Organize your project files as follows: + +```text +goat-celo-tutorial/ +├── src/ +│ ├── index.ts <- Main application file +│ └── tokens.ts <- Definitions for Celo tokens +├── .env <- Environment variables (KEEP THIS PRIVATE) +├── package.json +├── package-lock.json +└── tsconfig.json +``` + +## Code Implementation + +### 1. `src/tokens.ts`: + +This file defines the Celo tokens we'll be interacting with (CELO, cUSD, and USDC). + +```typescript +// src/tokens.ts +import { Token } from "@goat-sdk/plugin-erc20"; + +export const tokens: Token[] = [ + { + decimals: 6, + symbol: "USDC", + name: "USD Coin", + chains: { + "42220": { + contractAddress: "0xcebA9300f2b948710d2653dD7B07f33A8B32118C", + }, + }, + }, + { + decimals: 18, + symbol: "CELO", + name: "Celo", + chains: { + "42220": { + contractAddress: "0x471EcE3750Da237f93B8E339c536989b8978a438", + }, + }, + }, + { + decimals: 18, + symbol: "cUSD", + name: "Celo Dollar", + chains: { + "42220": { + contractAddress: "0x765de816845861e75a25fca122bb6898b8b1282a", + }, + }, + }, +]; +``` + +### 2. `src/index.ts`: + +This is the main application file where we set up GOAT, the wallet, and the interactive prompt. + +```typescript +// src/index.ts +import { openai } from "@ai-sdk/openai"; +import { getOnChainTools } from "@goat-sdk/adapter-vercel-ai"; +import { erc20 } from "@goat-sdk/plugin-erc20"; +import { viem } from "@goat-sdk/wallet-viem"; +import { generateText } from "ai"; +import dotenv from "dotenv"; +import readline from "node:readline"; +import { createWalletClient, http } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { celo } from "viem/chains"; +import { tokens } from "./tokens"; + +dotenv.config(); + +// --- Wallet Setup --- +const account = privateKeyToAccount( + process.env.WALLET_PRIVATE_KEY as `0x${string}`, +); + +const walletClient = createWalletClient({ + account: account, + transport: http(process.env.RPC_PROVIDER_URL), + chain: celo, +}); + +(async () => { + // --- GOAT Setup --- + const tools = await getOnChainTools({ + wallet: viem(walletClient), + plugins: [erc20({ tokens })], + }); + + // --- Interactive Prompt --- + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + while (true) { + const prompt = await new Promise((resolve) => { + rl.question('Enter your prompt (or "exit" to quit): ', resolve); + }); + + if (prompt === "exit") { + rl.close(); + break; + } + + try { + const result = await generateText({ + model: openai("gpt-4o"), // Use "gpt-4o" for better performance, or another model + tools: tools, + maxSteps: 10, // Maximum number of tool invocations per request + prompt: prompt, + onStepFinish: (event) => { + console.log(event.toolResults); // Log the results of each tool invocation + }, + }); + console.log(result.text); + } catch (error) { + console.error("An error occurred:", error); // Improved error handling + } + console.log("\n-------------------\n"); + } +})(); +``` + +### 3. `.env` + +Create a `.env` file in the root of your project and add the following, replacing the placeholders with your actual values: + +```bash +WALLET_PRIVATE_KEY=your_wallet_private_key +RPC_PROVIDER_URL=https://forno.celo.org # Or your preferred provider +OPENAI_API_KEY=your_openai_api_key +``` + +Important Security Note: Never commit your `.env` file or your private key to version control (e.g., Git). Add `.env` to your `.gitignore` file. + +## Running the Application + +Compile the TypeScript code: + +```bash +pnpm dev +``` + +The application will start, and you'll see the prompt: `Enter your prompt (or "exit" to quit):`. You can now enter natural language commands. + +## Example Prompts and Explanations + +Here are some example prompts you can use and explanations of what's happening: + +- "Transfer 1 cUSD to 0x13F6b54c5491cd4745fF4cFfaA9EfEe59E628657" + + - GOAT uses the `get_address` tool (implicitly, you don't need to specify it). + - It then uses `get_token_info_by_symbol` to find the cUSD token details. + - `convert_to_base_unit` converts 1 cUSD to its base unit (1 \* 10^18). + - Finally, the `transfer` tool is called with the token address, recipient, and amount. + - The transaction hash is returned. + +- "What is my allowance on USDC?" + + - `get_address` is called to get the user's address. + - `get_token_info_by_symbol` finds the USDC token. + - `get_chain` is used to get the current chain + - `get_token_allowance` is called to check the allowance of your address to spend USDC. The spender, in this case, is also your address, so you get 0. This is by design. + - The allowance amount is returned. + +- "Approve 0x13F6b54c5491cd4745fF4cFfaA9EfEe59E628657 to spend 10 USDC on my behalf" + + - This prompt would use the `approve` tool from the ERC-20 plugin. You'd see similar steps to the transfer, but instead of transferring, it would set an allowance for the specified address to spend your USDC. + +- "What is my CELO balance?" + + - `get_address` will be used to get the current user address. + - `get_token_info_by_symbol` finds the CELO token. + - `get_balance` is used to get the current address balance. + - The balance amount is returned. + +## Troubleshooting + +- `TypeError: Cannot read properties of undefined (reading 'call')` or similar errors: Double-check your `tsconfig.json` settings, particularly `module`, `target`, and `lib`. Make sure your Node.js version is compatible. Reinstall your dependencies (`rm -rf node_modules && npm install`). + +- `Error: Invalid ABI`: Ensure your contract addresses in `tokens.ts` are correct for the Celo network (chain ID 42220). + +- OpenAI API errors (e.g., 401 Unauthorized): Verify your `OPENAI_API_KEY` is correct and that your OpenAI account has sufficient credits. + +- Transaction failures: + + - Check that your wallet has enough CELO to pay for gas. + - Verify your `RPC_PROVIDER_URL` is correct and functioning. + - If you're using a custom RPC provider, ensure it supports the necessary methods. + +- Type errors after installation: If you encounter persistent type errors, you can try adding `// @ts-ignore` comments above the lines causing issues as a temporary workaround. However, it's best to resolve the underlying type issues if possible. The provided code avoids this, but it's a useful debugging technique. + +## Conclusion + +This tutorial demonstrated how to build a Celo blockchain AI agent with GOAT, Node.js, and TypeScript. You've learned to set up a project, integrate a wallet, define tokens, and use natural language to execute on-chain actions. This provides a foundation for creating powerful, user-friendly Web3 applications that simplify complex blockchain interactions. Remember to prioritize security and continue exploring the possibilities! + +## Next Steps + +- Explore more examples and documentation for GOAT and the ERC-20 plugin and ERC-721 plugin. +- Build a more complex application using GOAT and other Celo tools. +- Contribute to the GOAT project and provide feedback. diff --git a/blog/03-28-2023-introducing-prosperity-passport/introducing-prosperity-passport.md b/blog/03-28-2023-introducing-prosperity-passport/introducing-prosperity-passport.md index 35bb3c30ee..39d453bf7b 100644 --- a/blog/03-28-2023-introducing-prosperity-passport/introducing-prosperity-passport.md +++ b/blog/03-28-2023-introducing-prosperity-passport/introducing-prosperity-passport.md @@ -11,8 +11,6 @@ hide_table_of_contents: false slug: /tutorials/introducing-prosperity-passport-the-first-soulbound-token-powered-web3-identity-solution-for-celo-blockchain --- -![header](../../src/data-tutorials/showcase/beginner/introducing-prosperity-passport-the-first-soulbound-token-powered-web3-identity-solution-for-celo-blockchain.png) - ## 🌱 Introduction The rise of Web3 technologies has created new opportunities for decentralized identity solutions that provide more privacy, security, and control for users. One such solution is Prosperity Passport, the first soulbound token-powered identity solution for the Celo blockchain. @@ -93,4 +91,4 @@ Hi! My name is Kunal Dawar and I am a Full Stack web2/web3 Developer. I have par One thing that I am truly passionate about is creating things that are reliable and don't break easily. I believe that creating high-quality products is important not only for the users but also for the overall growth and success of a business. -In my free time, I enjoy learning about new technologies and staying up-to-date with the latest trends in the field. I also love to share my knowledge with others and mentor those who are interested in pursuing a career in web development. \ No newline at end of file +In my free time, I enjoy learning about new technologies and staying up-to-date with the latest trends in the field. I also love to share my knowledge with others and mentor those who are interested in pursuing a career in web development. diff --git a/blog/04-01-2023-How-To-Build-A-Multi-Signature-Wallet/How-To-Build-A-Multi-Signature-Wallet-Contract.md b/blog/04-01-2023-How-To-Build-A-Multi-Signature-Wallet/How-To-Build-A-Multi-Signature-Wallet-Contract.md deleted file mode 100644 index 4c21a09973..0000000000 --- a/blog/04-01-2023-How-To-Build-A-Multi-Signature-Wallet/How-To-Build-A-Multi-Signature-Wallet-Contract.md +++ /dev/null @@ -1,409 +0,0 @@ ---- -title: How To Build A Multi Signature Wallet Contract That Requires Multiple Approvals For Transactions On Celo -description: In this tutorial, we will walk through the process of building a multi-signature wallet contract using Solidity and Remix IDE -authors: - - name: ✍️ Jonathan Iheme - url: https://github.com/4undRaiser - image_url: https://avatars.githubusercontent.com/u/87926451?s=96&v=4 -tags: [celosage, solidity, celo, intermediate] -hide_table_of_contents: true -slug: "/tutorials/how-to-build-a-multi-signature-wallet-contract-that-requires-multiple-approvals-for-transactions-on-celo" ---- - -![header](../../src/data-tutorials/showcase/intermediate/how-to-build-a-multi-signature-wallet-contract-that-requires-multiple-approvals-for-transactions-on-celo.png) - -## Introduction - -A multi-signature wallet contract is a type of smart contract that requires multiple approvals before executing a transaction. This can be useful for organizations or groups that want to maintain shared control over funds or resources. In this tutorial we'll create a simple multi-signature wallet contract written with Solidity: - -Here's the github repo of our code. [source code](https://github.com/4undRaiser/celo-multi-signature-wallet) - -## Prerequisites - -To follow this tutorial, you will need the following: - -- Basic knowledge of Solidity programming language. -- A Development Environment Like Remix. -- The celo Extension Wallet. - -## SmartContract - -Let's begin writing our smart contract in Remix IDE - -The completed code Should look like this. - -```solidity - // SPDX-License-Identifier: MIT - pragma solidity ^0.8.0; - -contract MultiSigWallet { - address[] public owners; - uint256 public required; - - struct Transaction { - address destination; - uint256 value; - bytes data; - bool executed; - } - - mapping(uint256 => Transaction) public transactions; - mapping(uint256 => mapping(address => bool)) public confirmations; - uint256 public transactionCount; - - modifier validRequirement(uint256 _ownerCount, uint256 _required) { - require(_required > 0, "Required should be greater than 0"); - require(_ownerCount >= _required, "Owners count should be greater than or equal to required"); - _; - } - - modifier ownerExists(address _owner) { - require(isOwner(_owner), "Not an owner"); - _; - } - - modifier notNull(address _address) { - require(_address != address(0), "Address should not be null"); - _; - } - - constructor(address[] memory _owners, uint256 _required) validRequirement(_owners.length, _required) { - for (uint256 i = 0; i < _owners.length; i++) { - require(!isOwner(_owners[i]), "Duplicate owner"); - owners.push(_owners[i]); - } - required = _required; - } - - function isOwner(address _owner) public view returns (bool) { - for (uint256 i = 0; i < owners.length; i++) { - if (owners[i] == _owner) { - return true; - } - } - return false; - } - - function submitTransaction(address _destination, uint256 _value, bytes memory _data) - public - ownerExists(msg.sender) - notNull(_destination) - returns (uint256) - { - uint256 transactionId = addTransaction(_destination, _value, _data); - confirmTransaction(transactionId); - return transactionId; - } - - function confirmTransaction(uint256 _transactionId) public ownerExists(msg.sender) { - require(!confirmations[_transactionId][msg.sender], "Transaction already confirmed by this owner"); - confirmations[_transactionId][msg.sender] = true; - executeTransaction(_transactionId); - } - - function executeTransaction(uint256 _transactionId) public { - require(transactions[_transactionId].executed == false, "Transaction already executed"); - if (isConfirmed(_transactionId)) { - transactions[_transactionId].executed = true; - (bool success, ) = transactions[_transactionId].destination.call{value: transactions[_transactionId].value}( - transactions[_transactionId].data - ); - require(success, "Transaction execution failed"); - } - } - - function isConfirmed(uint256 _transactionId) public view returns (bool) { - uint256 count = 0; - for (uint256 i = 0; i < owners.length; i++) { - if (confirmations[_transactionId][owners[i]]) { - count += 1; - } - if (count == required) { - return true; - } - } - return false; - } - - function addTransaction(address _destination, uint256 _value, bytes memory _data) - internal - notNull(_destination) - returns (uint256) - { - uint256 transactionId = transactionCount; - transactions[transactionId] = Transaction({ - destination: _destination, - value: _value, - data: _data, - executed: false - }); - transactionCount += 1; - return transactionId; -} - -function getOwners() public view returns (address[] memory) { - return owners; -} - -function getTransaction(uint256 _transactionId) public view returns (address destination, uint256 value, bytes memory data, bool executed) { - Transaction memory transaction = transactions[_transactionId]; - return (transaction.destination, transaction.value, transaction.data, transaction.executed); -} - -function getConfirmationCount(uint256 _transactionId) public view returns (uint256) { - uint256 count = 0; - for (uint256 i = 0; i < owners.length; i++) { - if (confirmations[_transactionId][owners[i]]) { - count += 1; - } - } - return count; -} - -function isConfirmedBy(uint256 _transactionId, address _owner) public view returns (bool) { - return confirmations[_transactionId][_owner]; -} - -receive() external payable {} -} -``` - -### Breakdown - -First, we declared our license and the solidity version. - -```solidity -// SPDX-License-Identifier: MIT - pragma solidity ^0.8.0; -``` - -**State Variables** - -The state variables of the contract are defined next: - -```solidity -contract MultiSigWallet { - address[] public owners; - uint256 public required; - - struct Transaction { - address destination; - uint256 value; - bytes data; - bool executed; -} - -mapping(uint256 => Transaction) public transactions; -mapping(uint256 => mapping(address => bool)) public confirmations; -uint256 public transactionCount; - -} -``` - -The `owners` variable is an array of addresses that represent the owners of the multi-signature wallet. The `required` variable represents the number of signatures required to execute a transaction. - -The `Transaction` struct defines the properties of a transaction, including the destination address, value, data, and execution status. - -The `transactions` mapping stores the transactions by their IDs. The `confirmations` mapping stores the confirmations for each transaction by the owner address. The `transactionCount` variable keeps track of the number of transactions. - -**Modifiers** - -```solidity - modifier validRequirement(uint256 _ownerCount, uint256 _required) { - require(_required > 0, "Required should be greater than 0"); - require(_ownerCount >= _required, "Owners count should be greater than or equal to required"); - _; - } - - modifier ownerExists(address _owner) { - require(isOwner(_owner), "Not an owner"); - _; - } - - modifier notNull(address _address) { - require(_address != address(0), "Address should not be null"); - _; - } -``` - -Modifiers are used to add conditions to functions. The `validRequirement` modifier checks if the number of owners and the required number of signatures are valid. The `ownerExists` modifier checks if the address passed is one of the owners. The `notNull` modifier checks if an address is not null. - -**Constructor** - -```solidity - constructor(address[] memory _owners, uint256 _required) validRequirement(_owners.length, _required) { - for (uint256 i = 0; i < _owners.length; i++) { - require(!isOwner(_owners[i]), "Duplicate owner"); - owners.push(_owners[i]); - } - required = _required; - } -``` - -The constructor takes an array of addresses representing the owners and the required number of signatures. It calls the `validRequirement` modifier to check if the parameters are valid. - -The constructor adds each owner to the `owners` array and sets the required number of signatures. - -**Functions** - -The contract defines several functions: - -```solidity - function isOwner(address _owner) public view returns (bool) { - for (uint256 i = 0; i < owners.length; i++) { - if (owners[i] == _owner) { - return true; - } - } - return false; - } -``` - -The `isOwner` function checks if the address passed is one of the owners. - -```solidity - function submitTransaction(address _destination, uint256 _value, bytes memory _data) - public - ownerExists(msg.sender) - notNull(_destination) - returns (uint256) - { - uint256 transactionId = addTransaction(_destination, _value, _data); - confirmTransaction(transactionId); - return transactionId; - } -``` - -The `submitTransaction` function creates a new `transaction` and adds it to the transactions mapping using the `addTransaction` function. It then calls the `confirmTransaction` function to confirm the transaction. - -```solidity - function confirmTransaction(uint256 _transactionId) public ownerExists(msg.sender) { - require(!confirmations[_transactionId][msg.sender], "Transaction already confirmed by this owner"); - confirmations[_transactionId][msg.sender] = true; - executeTransaction(_transactionId); - } -``` - -The `confirmTransaction` function confirms a transaction by setting the confirmation for the transaction ID and the owner address to true. It then calls the `executeTransaction` function to execute the transaction if it has been confirmed by all required owners. - -```solidity - function executeTransaction(uint256 _transactionId) public { - require(transactions[_transactionId].executed == false, "Transaction already executed"); - if (isConfirmed(_transactionId)) { - transactions[_transactionId].executed = true; - (bool success, ) = transactions[_transactionId].destination.call{value: transactions[_transactionId].value}( - transactions[_transactionId].data - ); - require(success, "Transaction execution failed"); - } - } -``` - -The `executeTransaction` function executes a transaction if it has not been executed yet and if it has been confirmed by all required owners. It uses the `call` function to send the value and data to the destination address. - -```solidity - function isConfirmed(uint256 _transactionId) public view returns (bool) { - uint256 count = 0; - for (uint256 i = 0; i < owners.length; i++) { - if (confirmations[_transactionId][owners[i]]) { - count += 1; - } - if (count == required) { - return true; - } - } - return false; - } -``` - -The `isConfirmed` function checks if a transaction has been confirmed by all required owners. - -```solidity - function addTransaction(address _destination, uint256 _value, bytes memory _data) - internal - notNull(_destination) - returns (uint256) - { - uint256 transactionId = transactionCount; - transactions[transactionId] = Transaction({ - destination: _destination, - value: _value, - data: _data, - executed: false - }); - transactionCount += 1; - return transactionId; -} -``` - -The `addTransaction` function adds a new `transaction` to the transactions mapping and returns the transaction ID. - -```solidity -function getOwners() public view returns (address[] memory) { - return owners; -} -``` - -The `getOwners` function returns the array of owner addresses. - -```solidity -function getTransaction(uint256 _transactionId) public view returns (address destination, uint256 value, bytes memory data, bool executed) { - Transaction memory transaction = transactions[_transactionId]; - return (transaction.destination, transaction.value, transaction.data, transaction.executed); -} -``` - -The `getTransaction` function returns the properties of a transaction by its ID. - -```solidity -function getConfirmationCount(uint256 _transactionId) public view returns (uint256) { - uint256 count = 0; - for (uint256 i = 0; i < owners.length; i++) { - if (confirmations[_transactionId][owners[i]]) { - count += 1; - } - } - return count; -} -``` - -The `getConfirmationCount` function returns the number of confirmations for a transaction by its ID. - -```solidity -function isConfirmedBy(uint256 _transactionId, address _owner) public view returns (bool) { - return confirmations[_transactionId][_owner]; -} -``` - -The `isConfirmedBy` function checks if a transaction has been confirmed by a specific owner. - -```solidity -receive() external payable {} -``` - -The `receive` function allows the contract to receive Ether. - -## Deployment - -To deploy our smart contract successfully, we need the celo extention wallet which can be downloaded from [here](https://chrome.google.com/webstore/detail/celoextensionwallet/kkilomkmpmkbdnfelcpgckmpcaemjcdh?hl=en) - -Next, we need to fund our newly created wallet which can done using the celo alfojares faucet [Here](https://celo.org/developers/faucet) - -You can now fund your wallet and deploy your contract using the celo plugin in remix. - -## Conclusion - -In this tutorial, we created a MultiSigWallet contract written in Solidity. We have covered the state variables, modifiers, constructor, and functions in detail. This contract is an example of how multi-signature wallets can be implemented in decentralized applications to ensure secure and transparent management of funds. - -## Next Steps - -I hope you learned a lot from this tutorial. Here are some relevant links that would aid your learning further. - -- [Celo Docs](https://docs.celo.org/) -- [Solidity Docs](https://docs.soliditylang.org/en/v0.8.17/) - -## About the author - -I'm Jonathan Iheme, A full stack block-chain Developer from Nigeria. - -Thank You!! diff --git a/docs/cli/epochs.md b/docs/cli/epochs.md index a87b69c238..2b530fa06b 100644 --- a/docs/cli/epochs.md +++ b/docs/cli/epochs.md @@ -1,12 +1,12 @@ -`celocli epochs` -================ +# `celocli epochs` Finishes next epoch process. -* [`celocli epochs:finish`](#celocli-epochsfinish) -* [`celocli epochs:send-validator-payment`](#celocli-epochssend-validator-payment) -* [`celocli epochs:start`](#celocli-epochsstart) -* [`celocli epochs:switch`](#celocli-epochsswitch) +- [`celocli epochs`](#celocli-epochs) + - [`celocli epochs:finish` {#celocli-epochsfinish}](#celocli-epochsfinish-celocli-epochsfinish) + - [`celocli epochs:send-validator-payment` {#celocli-epochssend-validator-payment}](#celocli-epochssend-validator-payment-celocli-epochssend-validator-payment) + - [`celocli epochs:start` {#celocli-epochsstart}](#celocli-epochsstart-celocli-epochsstart) + - [`celocli epochs:switch` {#celocli-epochsswitch}](#celocli-epochsswitch-celocli-epochsswitch) ## `celocli epochs:finish` {#celocli-epochsfinish} diff --git a/docs/cli/network.md b/docs/cli/network.md index 0db993e405..04321271d5 100644 --- a/docs/cli/network.md +++ b/docs/cli/network.md @@ -1,14 +1,14 @@ -`celocli network` -================= +# `celocli network` View details about the network, like contracts and parameters -* [`celocli network:community-rpc-nodes`](#celocli-networkcommunity-rpc-nodes) -* [`celocli network:contracts`](#celocli-networkcontracts) -* [`celocli network:info`](#celocli-networkinfo) -* [`celocli network:parameters`](#celocli-networkparameters) -* [`celocli network:rpc-urls`](#celocli-networkrpc-urls) -* [`celocli network:whitelist`](#celocli-networkwhitelist) +- [`celocli network`](#celocli-network) + - [`celocli network:community-rpc-nodes` {#celocli-networkcommunity-rpc-nodes}](#celocli-networkcommunity-rpc-nodes-celocli-networkcommunity-rpc-nodes) + - [`celocli network:contracts` {#celocli-networkcontracts}](#celocli-networkcontracts-celocli-networkcontracts) + - [`celocli network:info` {#celocli-networkinfo}](#celocli-networkinfo-celocli-networkinfo) + - [`celocli network:parameters` {#celocli-networkparameters}](#celocli-networkparameters-celocli-networkparameters) + - [`celocli network:rpc-urls` {#celocli-networkrpc-urls}](#celocli-networkrpc-urls-celocli-networkrpc-urls) + - [`celocli network:whitelist` {#celocli-networkwhitelist}](#celocli-networkwhitelist-celocli-networkwhitelist) ## `celocli network:community-rpc-nodes` {#celocli-networkcommunity-rpc-nodes} diff --git a/docs/cli/node.md b/docs/cli/node.md index 54f2f64aa4..c412e9b5cb 100644 --- a/docs/cli/node.md +++ b/docs/cli/node.md @@ -1,11 +1,11 @@ -`celocli node` -============== +# `celocli node` Manage your Celo node -* [`celocli node:accounts`](#celocli-nodeaccounts) -* [`celocli node:list`](#celocli-nodelist) -* [`celocli node:synced`](#celocli-nodesynced) +- [`celocli node`](#celocli-node) + - [`celocli node:accounts` {#celocli-nodeaccounts}](#celocli-nodeaccounts-celocli-nodeaccounts) + - [`celocli node:list` {#celocli-nodelist}](#celocli-nodelist-celocli-nodelist) + - [`celocli node:synced` {#celocli-nodesynced}](#celocli-nodesynced-celocli-nodesynced) ## `celocli node:accounts` {#celocli-nodeaccounts} diff --git a/docs/cli/validator.md b/docs/cli/validator.md index 95392656ce..6f365035ff 100644 --- a/docs/cli/validator.md +++ b/docs/cli/validator.md @@ -1,23 +1,23 @@ -`celocli validator` -=================== +# `celocli validator` View and manage Validators -* [`celocli validator:affiliate ARG1`](#celocli-validatoraffiliate-arg1) -* [`celocli validator:community-rpc-nodes`](#celocli-validatorcommunity-rpc-nodes) -* [`celocli validator:deaffiliate`](#celocli-validatordeaffiliate) -* [`celocli validator:deregister`](#celocli-validatorderegister) -* [`celocli validator:downtime-slash`](#celocli-validatordowntime-slash) -* [`celocli validator:list`](#celocli-validatorlist) -* [`celocli validator:register`](#celocli-validatorregister) -* [`celocli validator:requirements`](#celocli-validatorrequirements) -* [`celocli validator:rpc-urls`](#celocli-validatorrpc-urls) -* [`celocli validator:send-payment`](#celocli-validatorsend-payment) -* [`celocli validator:set-bitmaps`](#celocli-validatorset-bitmaps) -* [`celocli validator:show ARG1`](#celocli-validatorshow-arg1) -* [`celocli validator:signed-blocks`](#celocli-validatorsigned-blocks) -* [`celocli validator:status`](#celocli-validatorstatus) -* [`celocli validator:update-bls-public-key`](#celocli-validatorupdate-bls-public-key) +- [`celocli validator`](#celocli-validator) + - [`celocli validator:affiliate ARG1` {#celocli-validatoraffiliate-arg1}](#celocli-validatoraffiliate-arg1-celocli-validatoraffiliate-arg1) + - [`celocli validator:community-rpc-nodes` {#celocli-validatorcommunity-rpc-nodes}](#celocli-validatorcommunity-rpc-nodes-celocli-validatorcommunity-rpc-nodes) + - [`celocli validator:deaffiliate` {#celocli-validatordeaffiliate}](#celocli-validatordeaffiliate-celocli-validatordeaffiliate) + - [`celocli validator:deregister` {#celocli-validatorderegister}](#celocli-validatorderegister-celocli-validatorderegister) + - [`celocli validator:downtime-slash` {#celocli-validatordowntime-slash}](#celocli-validatordowntime-slash-celocli-validatordowntime-slash) + - [`celocli validator:list` {#celocli-validatorlist}](#celocli-validatorlist-celocli-validatorlist) + - [`celocli validator:register` {#celocli-validatorregister}](#celocli-validatorregister-celocli-validatorregister) + - [`celocli validator:requirements` {#celocli-validatorrequirements}](#celocli-validatorrequirements-celocli-validatorrequirements) + - [`celocli validator:rpc-urls` {#celocli-validatorrpc-urls}](#celocli-validatorrpc-urls-celocli-validatorrpc-urls) + - [`celocli validator:send-payment` {#celocli-validatorsend-payment}](#celocli-validatorsend-payment-celocli-validatorsend-payment) + - [`celocli validator:set-bitmaps` {#celocli-validatorset-bitmaps}](#celocli-validatorset-bitmaps-celocli-validatorset-bitmaps) + - [`celocli validator:show ARG1` {#celocli-validatorshow-arg1}](#celocli-validatorshow-arg1-celocli-validatorshow-arg1) + - [`celocli validator:signed-blocks` {#celocli-validatorsigned-blocks}](#celocli-validatorsigned-blocks-celocli-validatorsigned-blocks) + - [`celocli validator:status` {#celocli-validatorstatus}](#celocli-validatorstatus-celocli-validatorstatus) + - [`celocli validator:update-bls-public-key` {#celocli-validatorupdate-bls-public-key}](#celocli-validatorupdate-bls-public-key-celocli-validatorupdate-bls-public-key) ## `celocli validator:affiliate ARG1` {#celocli-validatoraffiliate-arg1} diff --git a/docs/cli/validatorgroup.md b/docs/cli/validatorgroup.md index f3246feecc..b87bb02df6 100644 --- a/docs/cli/validatorgroup.md +++ b/docs/cli/validatorgroup.md @@ -1,17 +1,17 @@ -`celocli validatorgroup` -======================== +# `celocli validatorgroup` View and manage Validator Groups -* [`celocli validatorgroup:commission`](#celocli-validatorgroupcommission) -* [`celocli validatorgroup:community-rpc-nodes`](#celocli-validatorgroupcommunity-rpc-nodes) -* [`celocli validatorgroup:deregister`](#celocli-validatorgroupderegister) -* [`celocli validatorgroup:list`](#celocli-validatorgrouplist) -* [`celocli validatorgroup:member ARG1`](#celocli-validatorgroupmember-arg1) -* [`celocli validatorgroup:register`](#celocli-validatorgroupregister) -* [`celocli validatorgroup:reset-slashing-multiplier ARG1`](#celocli-validatorgroupreset-slashing-multiplier-arg1) -* [`celocli validatorgroup:rpc-urls`](#celocli-validatorgrouprpc-urls) -* [`celocli validatorgroup:show ARG1`](#celocli-validatorgroupshow-arg1) +- [`celocli validatorgroup`](#celocli-validatorgroup) + - [`celocli validatorgroup:commission` {#celocli-validatorgroupcommission}](#celocli-validatorgroupcommission-celocli-validatorgroupcommission) + - [`celocli validatorgroup:community-rpc-nodes` {#celocli-validatorgroupcommunity-rpc-nodes}](#celocli-validatorgroupcommunity-rpc-nodes-celocli-validatorgroupcommunity-rpc-nodes) + - [`celocli validatorgroup:deregister` {#celocli-validatorgroupderegister}](#celocli-validatorgroupderegister-celocli-validatorgroupderegister) + - [`celocli validatorgroup:list` {#celocli-validatorgrouplist}](#celocli-validatorgrouplist-celocli-validatorgrouplist) + - [`celocli validatorgroup:member ARG1` {#celocli-validatorgroupmember-arg1}](#celocli-validatorgroupmember-arg1-celocli-validatorgroupmember-arg1) + - [`celocli validatorgroup:register` {#celocli-validatorgroupregister}](#celocli-validatorgroupregister-celocli-validatorgroupregister) + - [`celocli validatorgroup:reset-slashing-multiplier ARG1` {#celocli-validatorgroupreset-slashing-multiplier-arg1}](#celocli-validatorgroupreset-slashing-multiplier-arg1-celocli-validatorgroupreset-slashing-multiplier-arg1) + - [`celocli validatorgroup:rpc-urls` {#celocli-validatorgrouprpc-urls}](#celocli-validatorgrouprpc-urls-celocli-validatorgrouprpc-urls) + - [`celocli validatorgroup:show ARG1` {#celocli-validatorgroupshow-arg1}](#celocli-validatorgroupshow-arg1-celocli-validatorgroupshow-arg1) ## `celocli validatorgroup:commission` {#celocli-validatorgroupcommission} diff --git a/docusaurus.config.js b/docusaurus.config.js index 4d49c40a28..71a624a620 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -340,7 +340,9 @@ module.exports = { theme: { customCss: require.resolve("./src/css/custom.css"), }, - blog: false, + blog: { + routeBasePath: "/all-blogs", + }, }, ], ], @@ -351,5 +353,9 @@ module.exports = { "sha384-Um5gpz1odJg5Z4HAmzPtgZKdTBHZdw8S29IecapCSB31ligYPhHQZMIlWLYQGVoc", crossorigin: "anonymous", }, + { + href: "/css/custom.css", + type: "text/css", + }, ], }; diff --git a/package.json b/package.json index 3ab3d0346c..c10526d88d 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "assert": "^2.0.0", "autoprefixer": "^10.4.13", "buffer": "^6.0.3", + "class-variance-authority": "^0.7.1", "clsx": "^2.0.0", "crypto-browserify": "^3.12.0", "docusaurus-plugin-fathom": "^1.1.0", diff --git a/src/components/Blog/BlogCard.tsx b/src/components/Blog/BlogCard.tsx new file mode 100644 index 0000000000..523d2eb91f --- /dev/null +++ b/src/components/Blog/BlogCard.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import DiscoverPattern from "../Homepage/Pattern/DiscoverPattern"; + +export const BlogCard = ({ title, description, image, link, index }) => { + return ( + +
+
+ {image ? ( + {title} + ) : ( +
+
+ +
+
+ )} +
+
+

+ {title} +

+

{description}

+
+
+
+ ); +}; diff --git a/src/components/Homepage/Button.tsx b/src/components/Homepage/Button.tsx new file mode 100644 index 0000000000..f95fed790c --- /dev/null +++ b/src/components/Homepage/Button.tsx @@ -0,0 +1,47 @@ +import { VariantProps, cva } from "class-variance-authority"; +import { ButtonHTMLAttributes, forwardRef } from "react"; + +import { cn } from "@site/src/utils/utils"; +import React from "react"; + +const buttonVariants = cva( + // Base styles applied to all variants + "border-solid inline-flex items-center justify-center rounded-md text-base font-bold transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 cursor-pointer", + { + variants: { + variant: { + default: "bg-violet-950 text-white hover:bg-violet-950/90 border-none", + outline: + "border-4 border-fig text-fig bg-transparent hover:bg-violet-950/10", + }, + size: { + default: "h-9 px-6 py-2", + sm: "h-8 px-4", + lg: "h-11 px-8", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +export interface ButtonProps + extends ButtonHTMLAttributes, + VariantProps {} + +const Button = forwardRef( + ({ className, variant, size, ...props }, ref) => { + return ( + + + + ); + })} + + + ); +} diff --git a/src/components/Homepage/DiscoverSection.tsx b/src/components/Homepage/DiscoverSection.tsx new file mode 100644 index 0000000000..9c5ddd2c9f --- /dev/null +++ b/src/components/Homepage/DiscoverSection.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import { Button } from "./Button"; +import DiscoverPattern from "./Pattern/DiscoverPattern"; + +export default function DiscoverSection() { + return ( +
+
+
+ Mobile app interface +
+
+ +
+
+
+
+
+ +
+

+ Discover what you can build on Celo +

+

+ Create apps for mobile wallets, social connections, AI agents, + funding, local stablecoins, and more! +

+
+ + +
+
+
+
+
+
+ ); +} diff --git a/src/components/Homepage/ExploreSection.tsx b/src/components/Homepage/ExploreSection.tsx new file mode 100644 index 0000000000..2d78acc3d9 --- /dev/null +++ b/src/components/Homepage/ExploreSection.tsx @@ -0,0 +1,80 @@ +import FeatureCard, { FeatureCardType } from "./FeatureCard"; + +import React from "react"; + +const features: FeatureCardType[] = [ + { + title: "Build for MiniPay", + description: + "Develop ultra-lightweight mobile dApps for Opera's self-custodial stablecoin wallet.", + image: "/img/build-for-minipay.png", + link: "#", + isReversed: false, + }, + { + title: "Extend and integrate with Self Protocol", + description: + "Map social identities like phone numbers to decentralized wallet addresses.", + image: "/img/self-protocol.png", + link: "#", + isReversed: true, + }, + { + title: "Tap into Stables", + description: + "Create stablecoin payment apps using Mento's local digital currencies.", + image: "/img/tap-into-stables.png", + link: "#", + isReversed: false, + }, + { + title: "Farcaster Frames", + description: + "Build Farcaster Frames for onchain activations with Warpcast.", + image: null, + link: "#", + isReversed: false, + }, + { + title: "Develop AI Agents", + description: + "Combine blockchain with AI to create decentralized autonomous agents.", + image: null, + link: "#", + isReversed: true, + }, + { + title: "Onchain Funding Apps", + description: + "Simplify funding with apps that ensure fairness, transparency, and global reach.", + image: null, + link: "#", + isReversed: false, + }, +]; + +export default function ExploreSection() { + return ( + <> +
+
+

+ Explore +

+
+ {features.map((feature, index) => ( + + ))} +
+
+
+
+ {features.map((feature, index) => ( + + ))} +
+ + ); +} diff --git a/src/components/Homepage/FeatureCard.tsx b/src/components/Homepage/FeatureCard.tsx new file mode 100644 index 0000000000..167567b1ab --- /dev/null +++ b/src/components/Homepage/FeatureCard.tsx @@ -0,0 +1,80 @@ +import React from "react"; +import DiscoverPattern from "./Pattern/DiscoverPattern"; + +export interface FeatureCardType { + title: string; + description: string; + image: string | null; + link: string; + isReversed?: boolean; +} + +export default function FeatureCard({ + title, + description, + image, + link, + index, + isReversed = false, +}: FeatureCardType & { index: number }) { + const isMobile = window.innerWidth < 768; + isMobile && (isReversed = false); + return ( + + <> + {isReversed ? ( +
+
+ {image ? ( + {title} + ) : ( +
+
+ +
+
+ )} +
+
+

+ {title} +

+

{description}

+
+
+ ) : ( +
+
+

+ {title} +

+

{description}

+
+
+ {image ? ( + {title} + ) : ( +
+
+ +
+
+ )} +
+
+ )} + +
+ ); +} diff --git a/src/components/Homepage/Footer.tsx b/src/components/Homepage/Footer.tsx new file mode 100644 index 0000000000..69a20f76ff --- /dev/null +++ b/src/components/Homepage/Footer.tsx @@ -0,0 +1,143 @@ +import React from "react"; +import { Button } from "./Button"; +import CeloLogo from "./icons/CeloLogo"; + +const footerLinks = { + docs: [ + { name: "Home", href: "#" }, + { name: "Docs GitHub", href: "#" }, + ], + community: [ + { name: "Contributors", href: "#" }, + { name: "Celo Signal Mailing List", href: "#" }, + { name: "Celo Signal Calendar", href: "#" }, + { name: "Community Calendar", href: "#" }, + ], + ecosystem: [ + { name: "Celo Foundation", href: "#" }, + { name: "Medium Blog", href: "#" }, + { name: "The Celo", href: "#" }, + { name: "Celo Hub", href: "#" }, + { name: "Career", href: "#" }, + ], + connect: [ + { name: "Discord", href: "#" }, + { name: "X (Twitter)", href: "#" }, + { name: "Reddit", href: "#" }, + ], +}; + +const communityLinks = [ + { + title: "Discord", + description: "Connect with the Community", + action: "Join our Discord →", + href: "#", + blockColor: ["prosperity", "lavender", "forest"], + }, + { + title: "Developer Events", + description: "Bring Your Ideas to Life", + action: "Register for Upcoming Hackathons →", + href: "#", + blockColor: ["white", "fig", "white"], + }, + { + title: "Celo Camp", + description: "Scale Your Project", + action: "Apply for Celo Camp →", + href: "#", + blockColor: ["forest", "sky", "forest"], + }, + { + title: "Grants", + description: "Explore Grants Opportunities", + action: "Learn about public goods funding programs →", + href: "#", + blockColor: ["disabled", "sand", "disabled"], + }, +]; + +export default function Footer() { + return ( +
+
+
+
+
+

+ Join the Celo ecosystem. +

+

+ Build together with a global community of passionate developers. +

+
+
+

+ Sign up for developer updates +

+
+ Email* + +
+
+
+ +
+ {communityLinks.map((link, index) => ( +
+ {index === 0 && ( +
+
+
+
+
+ )} + {index === 1 && ( +
+
+
+
+
+ )} + {index === 2 && ( +
+
+
+
+
+ )} + {index === 3 && ( +
+
+
+
+
+ )} +
+

+ {link.title} +

+

+ {link.description} +

+ +
+
+ ))} +
+
+ +
+
+ ); +} diff --git a/src/components/Homepage/GridPattern.tsx b/src/components/Homepage/GridPattern.tsx new file mode 100644 index 0000000000..00a40aa068 --- /dev/null +++ b/src/components/Homepage/GridPattern.tsx @@ -0,0 +1,29 @@ +import React from "react"; + +export default function GridPattern({ + className = "", +}: { + className?: string; +}) { + return ( + + + + + + + + + ); +} diff --git a/src/components/Homepage/Pattern/DiscoverPattern.tsx b/src/components/Homepage/Pattern/DiscoverPattern.tsx new file mode 100644 index 0000000000..68406424d7 --- /dev/null +++ b/src/components/Homepage/Pattern/DiscoverPattern.tsx @@ -0,0 +1,24 @@ +import React from "react"; + +export default function DiscoverPattern() { + return ( + + + + + + + + + + + + + ); +} diff --git a/src/components/Homepage/Pattern/DiscoverPatternAlt.tsx b/src/components/Homepage/Pattern/DiscoverPatternAlt.tsx new file mode 100644 index 0000000000..f8d6052a1e --- /dev/null +++ b/src/components/Homepage/Pattern/DiscoverPatternAlt.tsx @@ -0,0 +1,94 @@ +import React from "react"; + +export default function DiscoverPatternAlt() { + return ( + + + + + + + + + + + + + ); +} diff --git a/src/components/Homepage/StartBuilding.tsx b/src/components/Homepage/StartBuilding.tsx new file mode 100644 index 0000000000..343830baca --- /dev/null +++ b/src/components/Homepage/StartBuilding.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { Button } from "./Button"; + +export default function StartBuilding() { + return ( +
+
+ + Coming Soon + + + Celo L1 to Ethereum L2 Migration + + +
+ +

+ Start Building +

+

+ Get started with these developer tools and resources. +

+ +
+ ); +} diff --git a/src/components/Homepage/icons/CeloLogo.tsx b/src/components/Homepage/icons/CeloLogo.tsx new file mode 100644 index 0000000000..fecc898a60 --- /dev/null +++ b/src/components/Homepage/icons/CeloLogo.tsx @@ -0,0 +1,46 @@ +import React from "react"; + +export default function CeloLogo() { + return ( + + + + + + + + + + + + + + ); +} diff --git a/src/components/Homepage/icons/ComposerCliIcon.tsx b/src/components/Homepage/icons/ComposerCliIcon.tsx new file mode 100644 index 0000000000..87a2843806 --- /dev/null +++ b/src/components/Homepage/icons/ComposerCliIcon.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +export default function ComposerCliIcon({ className }: { className?: string }) { + return ( + + + + ); +} diff --git a/src/components/Homepage/icons/LearnIcon.tsx b/src/components/Homepage/icons/LearnIcon.tsx new file mode 100644 index 0000000000..28ef974161 --- /dev/null +++ b/src/components/Homepage/icons/LearnIcon.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +export default function LearnIcon({ className }: { className?: string }) { + return ( + + + + ); +} diff --git a/src/components/Homepage/icons/NetworkIcon.tsx b/src/components/Homepage/icons/NetworkIcon.tsx new file mode 100644 index 0000000000..fa3a828dcb --- /dev/null +++ b/src/components/Homepage/icons/NetworkIcon.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +export default function NetworkIcon({ className }: { className?: string }) { + return ( + + + + ); +} diff --git a/src/components/Homepage/icons/SmartPhoneIcon.tsx b/src/components/Homepage/icons/SmartPhoneIcon.tsx new file mode 100644 index 0000000000..82ca29ee38 --- /dev/null +++ b/src/components/Homepage/icons/SmartPhoneIcon.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +export default function SmartPhoneIcon({ className }: { className?: string }) { + return ( + + + + ); +} diff --git a/src/css/custom.css b/src/css/custom.css index c29c217a03..2784bfa408 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -2,6 +2,20 @@ @tailwind components; @tailwind utilities; +@font-face { + font-family: "Advercase"; + font-weight: bold; + font-style: normal; + src: url("/fonts/advercase-bold.woff2") format("woff2"); +} + +@font-face { + font-family: "Advercase"; + font-weight: normal; + font-style: normal; + src: url("/fonts/advercase-regular.woff2") format("woff2"); +} + /* stylelint-disable docusaurus/copyright-header */ /** * Any CSS included here will be global. The classic template diff --git a/src/data-home/showcase/celo-sage.png b/src/data-home/showcase/celo-sage.png deleted file mode 100644 index edd537134e..0000000000 Binary files a/src/data-home/showcase/celo-sage.png and /dev/null differ diff --git a/src/data-home/showcase/developers/build-on-celo.webp b/src/data-home/showcase/developers/build-on-celo.webp deleted file mode 100644 index 1257932ec3..0000000000 Binary files a/src/data-home/showcase/developers/build-on-celo.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/build-with-celo-2.webp b/src/data-home/showcase/developers/build-with-celo-2.webp deleted file mode 100644 index d74ccecbae..0000000000 Binary files a/src/data-home/showcase/developers/build-with-celo-2.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/build-with-celo.webp b/src/data-home/showcase/developers/build-with-celo.webp deleted file mode 100644 index 05c4dde653..0000000000 Binary files a/src/data-home/showcase/developers/build-with-celo.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/celo-composer.webp b/src/data-home/showcase/developers/celo-composer.webp deleted file mode 100644 index d95bbcaf9d..0000000000 Binary files a/src/data-home/showcase/developers/celo-composer.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/cli.webp b/src/data-home/showcase/developers/cli.webp deleted file mode 100644 index 5e68a38cb2..0000000000 Binary files a/src/data-home/showcase/developers/cli.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/deploy-on-celo.webp b/src/data-home/showcase/developers/deploy-on-celo.webp deleted file mode 100644 index 0dfe9570e9..0000000000 Binary files a/src/data-home/showcase/developers/deploy-on-celo.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/libraries-and-sdks.webp b/src/data-home/showcase/developers/libraries-and-sdks.webp deleted file mode 100644 index b08b4c2ebc..0000000000 Binary files a/src/data-home/showcase/developers/libraries-and-sdks.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/native-sdks.webp b/src/data-home/showcase/developers/native-sdks.webp deleted file mode 100644 index 3a3f435bf3..0000000000 Binary files a/src/data-home/showcase/developers/native-sdks.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/sdks.webp b/src/data-home/showcase/developers/sdks.webp deleted file mode 100644 index fa54d4f092..0000000000 Binary files a/src/data-home/showcase/developers/sdks.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/setup-environment.webp b/src/data-home/showcase/developers/setup-environment.webp deleted file mode 100644 index 57340818ad..0000000000 Binary files a/src/data-home/showcase/developers/setup-environment.webp and /dev/null differ diff --git a/src/data-home/showcase/developers/start-building.webp b/src/data-home/showcase/developers/start-building.webp deleted file mode 100644 index 91831a29c5..0000000000 Binary files a/src/data-home/showcase/developers/start-building.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/basic-concepts.webp b/src/data-home/showcase/favorites/basic-concepts.webp deleted file mode 100644 index 70190b6df4..0000000000 Binary files a/src/data-home/showcase/favorites/basic-concepts.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/dapps.webp b/src/data-home/showcase/favorites/dapps.webp deleted file mode 100644 index 94e8f04a68..0000000000 Binary files a/src/data-home/showcase/favorites/dapps.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/developers.webp b/src/data-home/showcase/favorites/developers.webp deleted file mode 100644 index 2e043733a3..0000000000 Binary files a/src/data-home/showcase/favorites/developers.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/explore-tutorials.webp b/src/data-home/showcase/favorites/explore-tutorials.webp deleted file mode 100644 index 37bd84d114..0000000000 Binary files a/src/data-home/showcase/favorites/explore-tutorials.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/feedback.webp b/src/data-home/showcase/favorites/feedback.webp deleted file mode 100644 index 1a998aabf7..0000000000 Binary files a/src/data-home/showcase/favorites/feedback.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/integrations.webp b/src/data-home/showcase/favorites/integrations.webp deleted file mode 100644 index 47f43b548d..0000000000 Binary files a/src/data-home/showcase/favorites/integrations.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/tutorials.webp b/src/data-home/showcase/favorites/tutorials.webp deleted file mode 100644 index 3528c5d7bc..0000000000 Binary files a/src/data-home/showcase/favorites/tutorials.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/use-a-dapp.webp b/src/data-home/showcase/favorites/use-a-dapp.webp deleted file mode 100644 index 58f07dec6c..0000000000 Binary files a/src/data-home/showcase/favorites/use-a-dapp.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/validators.webp b/src/data-home/showcase/favorites/validators.webp deleted file mode 100644 index e92ba86d91..0000000000 Binary files a/src/data-home/showcase/favorites/validators.webp and /dev/null differ diff --git a/src/data-home/showcase/favorites/wallets.webp b/src/data-home/showcase/favorites/wallets.webp deleted file mode 100644 index e3ef58161d..0000000000 Binary files a/src/data-home/showcase/favorites/wallets.webp and /dev/null differ diff --git a/src/data-home/showcase/integrations/bridges.webp b/src/data-home/showcase/integrations/bridges.webp deleted file mode 100644 index fa526370ec..0000000000 Binary files a/src/data-home/showcase/integrations/bridges.webp and /dev/null differ diff --git a/src/data-home/showcase/integrations/contract-addresses.webp b/src/data-home/showcase/integrations/contract-addresses.webp deleted file mode 100644 index 300b0e4bbd..0000000000 Binary files a/src/data-home/showcase/integrations/contract-addresses.webp and /dev/null differ diff --git a/src/data-home/showcase/integrations/deploy-smart-contracts.webp b/src/data-home/showcase/integrations/deploy-smart-contracts.webp deleted file mode 100644 index b2bfac723d..0000000000 Binary files a/src/data-home/showcase/integrations/deploy-smart-contracts.webp and /dev/null differ diff --git a/src/data-home/showcase/integrations/integration-checklist.webp b/src/data-home/showcase/integrations/integration-checklist.webp deleted file mode 100644 index 076c913325..0000000000 Binary files a/src/data-home/showcase/integrations/integration-checklist.webp and /dev/null differ diff --git a/src/data-home/showcase/integrations/listings.webp b/src/data-home/showcase/integrations/listings.webp deleted file mode 100644 index 96aec0e351..0000000000 Binary files a/src/data-home/showcase/integrations/listings.webp and /dev/null differ diff --git a/src/data-home/showcase/integrations/network-details.webp b/src/data-home/showcase/integrations/network-details.webp deleted file mode 100644 index d870e98af9..0000000000 Binary files a/src/data-home/showcase/integrations/network-details.webp and /dev/null differ diff --git a/src/data-home/showcase/integrations/oracles.webp b/src/data-home/showcase/integrations/oracles.webp deleted file mode 100644 index c7f4aeb358..0000000000 Binary files a/src/data-home/showcase/integrations/oracles.webp and /dev/null differ diff --git a/src/data-home/showcase/integrations/run-a-full-node.webp b/src/data-home/showcase/integrations/run-a-full-node.webp deleted file mode 100644 index 8603097851..0000000000 Binary files a/src/data-home/showcase/integrations/run-a-full-node.webp and /dev/null differ diff --git a/src/data-home/showcase/validators/nodes-and-services.webp b/src/data-home/showcase/validators/nodes-and-services.webp deleted file mode 100644 index 664602b1a4..0000000000 Binary files a/src/data-home/showcase/validators/nodes-and-services.webp and /dev/null differ diff --git a/src/data-home/showcase/validators/run-a-validator.webp b/src/data-home/showcase/validators/run-a-validator.webp deleted file mode 100644 index 93e14e809a..0000000000 Binary files a/src/data-home/showcase/validators/run-a-validator.webp and /dev/null differ diff --git a/src/data-home/showcase/validators/validator-tools.webp b/src/data-home/showcase/validators/validator-tools.webp deleted file mode 100644 index f7a0e06407..0000000000 Binary files a/src/data-home/showcase/validators/validator-tools.webp and /dev/null differ diff --git a/src/data-home/showcase/validators/voting-policy.webp b/src/data-home/showcase/validators/voting-policy.webp deleted file mode 100644 index 40f63ffbdd..0000000000 Binary files a/src/data-home/showcase/validators/voting-policy.webp and /dev/null differ diff --git a/src/data-home/users.tsx b/src/data-home/users.tsx deleted file mode 100644 index 3de566685b..0000000000 --- a/src/data-home/users.tsx +++ /dev/null @@ -1,280 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -/* eslint-disable global-require */ - -import { translate } from "@docusaurus/Translate"; -import { sortBy } from "@site/src/utils/jsUtils"; - -/* - * ADD YOUR SITE TO THE DOCUSAURUS SHOWCASE: - * - * Requirements for adding your site to our showcase: - * - It is a production-ready site with real content and decent customizations - * (different from the init templates) - * - It is NOT a work-in-progress with empty pages - * - It has a stable domain (a Netlify/Vercel deploy preview is not allowed) - * - * Instructions: - * - Add your site in the json array below - * - `title` is your project's name (no need for the "Docs" suffix) - * - A short (≤120 characters) description of your project - * - Use relevant tags to categorize your site (read the tag descriptions below) - * - Add a local image preview (decent screenshot of your Docusaurus site) - * - The image MUST be added to the GitHub repository, and use `require("img")` - * - The image has to have minimum width 640 and an aspect of no wider than 2:1 - * - If your website is open-source, add your source link. The link should open - * to a directory containing the `docusaurus.config.js` file - * - Open a PR and check for reported CI errors - * - * Example PR: https://github.com/facebook/docusaurus/pull/3976 - * - * If you edit this file through the GitHub interface, you can: - * - Submit first your users.tsx edit PR - * - This will create a branch on your Docusaurus fork (usually "patch-1") - * - Go to https://github.com//docusaurus/tree//website/src/data/showcase - * - Drag-and-drop an image here to add it to your existing PR - * - * Please help us maintain this showcase page data: - * - Update sites with wrong data - * - Ensure site tags remain correct over time - * - Remove sites not using Docusaurus anymore - * - Add missing Docusaurus sites (if the site owner agreed) - */ - -export type Tag = { - label: string; - description: string; - color: string; -}; - -export type TagType = - | "popular" - | "favorite" - | "developers" - | "integrations" - | "validators"; - -export type User = { - title: string; - description: string; - preview: string; - website: string; - source?: string | null; - tags: TagType[]; -}; - -// LIST OF AVAILABLE TAGS -// Available tags to assign to your site -// Please choose all tags that you think might apply. -// We'll remove inappropriate tags, but it's less likely that we add tags. -export const Tags: { [type in TagType]: Tag } = { - // DO NOT USE THIS TAG: we choose sites to add to appss - popular: { - label: translate({ message: "Favorite" }), - description: translate({ - message: "", - id: "showcase.tag.popular.description", - }), - color: "#e9669e", - }, - favorite: { - label: translate({ message: "Favorite" }), - description: translate({ - message: "", - id: "showcase.tag.favorite.description", - }), - color: "#35D07F", - }, - developers: { - label: translate({ message: "Developers" }), - description: translate({ - message: "", - id: "showcase.tag.developers.description", - }), - color: "#35D07F", - }, - integrations: { - label: translate({ message: "Integrations" }), - description: translate({ - message: "", - id: "showcase.tag.integrations.description", - }), - color: "#35D07F", - }, - validators: { - label: translate({ message: "Validators" }), - description: translate({ - message: "", - id: "showcase.tag.validators.description", - }), - color: "#35D07F", - }, -}; - -// Add your site to this list -// prettier-ignore -const Users: User[] = [ - - // Get Started with Celo - { - title: ' Choose a Wallet', - description: 'Connect to Celo and manage your funds with a wallet.', - preview: require('./showcase/favorites/wallets.webp'), - website: '/wallet', - tags: ['favorite'], - }, - { - title: ' Use a DApp', - description: 'Find and use decentralized applications on the Celo Network.', - preview: require('./showcase/favorites/dapps.webp'), - website: '/showcase', - tags: ['favorite'], - }, - { - title: ' Basic Concepts', - description: "Get started with the basics of the Celo platform.", - preview: require('./showcase/favorites/basic-concepts.webp'), - website: '/general', - tags: ['favorite'], - }, - - // Developers - { - title: ' Build a DApp', - description: 'Build and deploy decentralized applications on Celo.', - preview: require('./showcase/developers/build-with-celo.webp'), - website: '/developer/deploy', - tags: ['developers'], - }, - { - title: ' Setup Environment', - description: 'Get started with Celo by setting up your developer environment.', - preview: require('./showcase/developers/setup-environment.webp'), - website: '/developer/setup/overview', - tags: ['developers'], - }, - { - title: 'Libraries & SDKs', - description: 'Extend your Celo DApps with Celo libraries and SDKs.', - preview: require('./showcase/developers/libraries-and-sdks.webp'), - website: '../developer/sdks/celo-sdks', - tags: ['developers'], - }, - { - title: 'CLI', - description: 'Interact with the Celo protocol using a command line interface.', - preview: require('./showcase/developers/cli.webp'), - website: '/cli', - tags: ['developers'], - }, - - // Validators - { - title: 'Run a Validator', - description: 'How to get a Validator node running on the Celo Mainnet.', - preview: require('./showcase/validators/run-a-validator.webp'), - website: '/validator/run/mainnet', - tags: ['validators'], - }, - { - title: 'Nodes and Services', - description: 'Connect to nodes and services in the Celo Ecosystem.', - preview: require('./showcase/validators/nodes-and-services.webp'), - website: '/network/node/overview', - tags: ['validators'], - }, - { - title: 'Validator Tools', - description: 'Recommendations for running secure Celo nodes and services.', - preview: require('./showcase/validators/validator-tools.webp'), - website: '/validator/security', - tags: ['validators'], - }, - { - title: 'Voting Policy', - description: 'How the Celo Foundation allocates its votes to validator groups.', - preview: require('./showcase/validators/voting-policy.webp'), - website: '/validator/celo-foundation-voting-policy', - tags: ['validators'], - }, - - // Integrations - { - title: 'Run a Full Node', - description: 'Set up and run your own node on the Celo Network.', - preview: require('./showcase/integrations/run-a-full-node.webp'), - website: '/network/node/run-mainnet', - tags: ['integrations'], - }, - { - title: 'Deploy Smart Contracts', - description: 'How to deploy smart contracts on the Celo network.', - preview: require('./showcase/integrations/deploy-smart-contracts.webp'), - website: '/developer/deploy', - tags: ['integrations'], - }, - { - title: 'Network Details', - description: 'Overview of Celo Mainnet, Alfajores Testnet, and Baklava Testnet.', - preview: require('./showcase/integrations/network-details.webp'), - website: '/network', - tags: ['integrations'], - }, - { - title: 'Integration Checklist', - description: 'Checklist for applications building and integrating on Celo.', - preview: require('./showcase/integrations/integration-checklist.webp'), - website: '/integration/checklist', - tags: ['integrations'], - }, - { - title: 'Bridges', - description: 'Bridge assets from other chains to and from Celo.', - preview: require('./showcase/integrations/bridges.webp'), - website: '/protocol/bridge', - tags: ['integrations'], - }, - { - title: 'Oracles', - description: 'Connect Celo to outside sources with an oracle.', - preview: require('./showcase/integrations/oracles.webp'), - website: '/protocol/oracle', - tags: ['integrations'], - }, - { - title: 'Listings', - description: 'Support for digital asset exchanges or ranking sites.', - preview: require('./showcase/integrations/listings.webp'), - website: '/integration/listings', - tags: ['integrations'], - }, - { - title: 'Contract Addresses', - description: 'Core contract address proxies and implementations for the Celo network.', - preview: require('./showcase/integrations/contract-addresses.webp'), - website: '/contract-addresses', - tags: ['integrations'], - }, - - /* - Pro Tip: add your site in alphabetical order. - Appending your site here (at the end) is more likely to produce Git conflicts. - */ -]; - -export const TagList = Object.keys(Tags) as TagType[]; -function sortUsers() { - let result = Users; - // Sort by site name - result = sortBy(result, (user) => user.title.toLowerCase()); - // Sort by apps tag, popular first - result = sortBy(result, (user) => !user.tags.includes("favorite")); - return result; -} - -export const sortedUsers = sortUsers(); diff --git a/src/pages/blog/blogs.tsx b/src/pages/blog/blogs.tsx new file mode 100644 index 0000000000..df91557e2a --- /dev/null +++ b/src/pages/blog/blogs.tsx @@ -0,0 +1,9 @@ +export const blogs = [ + { + title: "Using Thirdweb Insight on Celo", + description: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry.", + image: "/blog/using-thirdweb-insight-on-celo.png", + link: "#", + }, +]; diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx new file mode 100644 index 0000000000..0bd4f670e0 --- /dev/null +++ b/src/pages/blog/index.tsx @@ -0,0 +1,77 @@ +import React, { useEffect } from "react"; + +/** + * Copyright (c) Facebook, Inc. and its affiliat es. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import Head from "@docusaurus/Head"; +import { translate } from "@docusaurus/Translate"; +import { BlogCard } from "@site/src/components/Blog/BlogCard"; +import Layout from "@theme/Layout"; +import { useLocation } from "react-router-dom"; +import { blogs } from "./blogs"; + +const TITLE = translate({ message: "Celo Documentation" }); +const DESCRIPTION = translate({ + message: + "Build decentralized applications that create the conditions for prosperity — for everyone.", +}); +const EDIT_URL = "/developer/deploy"; + +type UserState = { + scrollTopPosition: number; + focusedElementId: string | undefined; +}; + +function restoreUserState(userState: UserState | null) { + const { scrollTopPosition, focusedElementId } = userState ?? { + scrollTopPosition: 0, + focusedElementId: undefined, + }; + document.getElementById(focusedElementId)?.focus(); + window.scrollTo({ top: scrollTopPosition }); +} + +export default function HomePage(): JSX.Element { + const location = useLocation(); + useEffect(() => { + restoreUserState(location.state); + }, [location]); + + return ( + + + + + + + + +
+
+
+

+ All blogs +

+
+ {blogs.map((blog, index) => ( + + ))} +
+
+
+
+
+ ); +} diff --git a/src/pages/home/_components/ShowcaseCard/index.tsx b/src/pages/home/_components/ShowcaseCard/index.tsx deleted file mode 100644 index 813417fbd9..0000000000 --- a/src/pages/home/_components/ShowcaseCard/index.tsx +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import Link from "@docusaurus/Link"; -import Translate from "@docusaurus/Translate"; -import { - TagList, - Tags, - type Tag, - type TagType, - type User, -} from "@site/src/data-home/users"; -import { sortBy } from "@site/src/utils/jsUtils"; -import Image from "@theme/IdealImage"; -import clsx from "clsx"; -import React from "react"; -import Tooltip from "../ShowcaseTooltip"; -import styles from "./styles.module.css"; - -const TagComp = React.forwardRef( - ({ label, color, description }, ref) => ( -
  • - {label.toLowerCase()} - -
  • - ) -); - -function ShowcaseCardTag({ tags }: { tags: TagType[] }) { - const tagObjects = tags.map((tag) => ({ tag, ...Tags[tag] })); - - // Keep same order for all tags - const tagObjectsSorted = sortBy(tagObjects, (tagObject) => - TagList.indexOf(tagObject.tag) - ); - - return ( - <> - {tagObjectsSorted.map((tagObject, index) => { - const id = `showcase_card_tag_${tagObject.tag}`; - - return ( - - - - ); - })} - - ); -} - -function ShowcaseCard({ user }: { user: User }) { - return ( -
  • -
    - {user.title} -
    -
    -
    -

    - - {user.title} - -

    - {user.tags.includes("developers")} - {user.source && ( - - source - - )} -
    -

    {user.description}

    -
    -
      - {/* */} -
    -
  • - ); -} - -export default React.memo(ShowcaseCard); diff --git a/src/pages/home/_components/ShowcaseCard/styles.module.css b/src/pages/home/_components/ShowcaseCard/styles.module.css deleted file mode 100644 index 53c8903426..0000000000 --- a/src/pages/home/_components/ShowcaseCard/styles.module.css +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -.showcaseCardImage { - overflow: hidden; - height: 150px; - border-bottom: 2px solid var(--ifm-color-emphasis-200); -} - -.showcaseCardHeader { - display: flex; - align-items: center; - margin-bottom: 12px; -} - -.showcaseCardTitle { - margin-bottom: 0; - flex: 1 1 auto; -} - -.showcaseCardTitle a { - text-decoration: none; - background: linear-gradient( - var(--ifm-color-primary), - var(--ifm-color-primary) - ) - 0% 100% / 0% 1px no-repeat; - transition: background-size ease-out 200ms; -} - -.showcaseCardTitle a:not(:focus):hover { - background-size: 100% 1px; -} - -.showcaseCardTitle, -.showcaseCardHeader .svgIconFavorite { - margin-right: 0.25rem; -} - -.showcaseCardHeader .svgIconFavorite { - color: var(--site-color-svg-icon-favorite); -} - -.showcaseCardSrcBtn { - margin-left: 6px; - padding-left: 12px; - padding-right: 12px; - border: none; -} - -.showcaseCardSrcBtn:focus-visible { - background-color: var(--ifm-color-secondary-dark); -} - -[data-theme="dark"] .showcaseCardSrcBtn { - background-color: var(--ifm-color-emphasis-200) !important; - color: inherit; -} - -[data-theme="dark"] .showcaseCardSrcBtn:hover { - background-color: var(--ifm-color-emphasis-300) !important; -} - -.showcaseCardBody { - font-size: smaller; - line-height: 1.66; -} - -.cardFooter { - display: flex; - flex-wrap: wrap; -} - -.tag { - font-size: 0.675rem; - border: 1px solid var(--ifm-color-secondary-darkest); - cursor: default; - margin-right: 6px; - margin-bottom: 6px !important; - border-radius: 12px; - display: inline-flex; - align-items: center; -} - -.tag .textLabel { - margin-left: 8px; -} - -.tag .colorLabel { - width: 7px; - height: 7px; - border-radius: 50%; - margin-left: 6px; - margin-right: 6px; -} diff --git a/src/pages/home/_components/ShowcaseFilterToggle/index.tsx b/src/pages/home/_components/ShowcaseFilterToggle/index.tsx deleted file mode 100644 index bd8ef9c3d6..0000000000 --- a/src/pages/home/_components/ShowcaseFilterToggle/index.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect, useCallback } from "react"; -import clsx from "clsx"; -import { useHistory, useLocation } from "@docusaurus/router"; - -import { prepareUserState } from "../../index"; - -import styles from "./styles.module.css"; - -export type Operator = "OR" | "AND"; - -export const OperatorQueryKey = "operator"; - -export function readOperator(search: string): Operator { - return (new URLSearchParams(search).get(OperatorQueryKey) ?? - "OR") as Operator; -} - -export default function ShowcaseFilterToggle(): JSX.Element { - const id = "showcase_filter_toggle"; - const location = useLocation(); - const history = useHistory(); - const [operator, setOperator] = useState(false); - useEffect(() => { - setOperator(readOperator(location.search) === "AND"); - }, [location]); - const toggleOperator = useCallback(() => { - setOperator((o) => !o); - const searchParams = new URLSearchParams(location.search); - searchParams.delete(OperatorQueryKey); - if (!operator) { - searchParams.append(OperatorQueryKey, "AND"); - } - history.push({ - ...location, - search: searchParams.toString(), - state: prepareUserState(), - }); - }, [operator, location, history]); - - return ( -
    - { - if (e.key === "Enter") { - toggleOperator(); - } - }} - checked={operator} - /> - -
    - ); -} diff --git a/src/pages/home/_components/ShowcaseFilterToggle/styles.module.css b/src/pages/home/_components/ShowcaseFilterToggle/styles.module.css deleted file mode 100644 index e1a2d27e2c..0000000000 --- a/src/pages/home/_components/ShowcaseFilterToggle/styles.module.css +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -.checkboxLabel { - --height: 25px; - --width: 80px; - --border: 2px; - display: flex; - width: var(--width); - height: var(--height); - position: relative; - border-radius: var(--height); - border: var(--border) solid var(--ifm-color-primary-darkest); - cursor: pointer; - justify-content: space-around; - opacity: 0.75; - transition: opacity var(--ifm-transition-fast) - var(--ifm-transition-timing-default); - box-shadow: var(--ifm-global-shadow-md); -} - -.checkboxLabel:hover { - opacity: 1; - box-shadow: var(--ifm-global-shadow-md), - 0 0 2px 1px var(--ifm-color-primary-dark); -} - -.checkboxLabel::after { - position: absolute; - content: ""; - inset: 0; - width: calc(var(--width) / 2); - height: 100%; - border-radius: var(--height); - background-color: var(--ifm-color-primary-darkest); - transition: transform var(--ifm-transition-fast) - var(--ifm-transition-timing-default); - transform: translateX(calc(var(--width) / 2 - var(--border))); -} - -input:focus-visible ~ .checkboxLabel::after { - outline: 2px solid currentColor; -} - -.checkboxLabel > * { - font-size: 0.8rem; - color: inherit; - transition: opacity 150ms ease-in 50ms; -} - -input:checked ~ .checkboxLabel::after { - transform: translateX(calc(-1 * var(--border))); -} diff --git a/src/pages/home/_components/ShowcaseTagSelect/index.tsx b/src/pages/home/_components/ShowcaseTagSelect/index.tsx deleted file mode 100644 index 8d753a2905..0000000000 --- a/src/pages/home/_components/ShowcaseTagSelect/index.tsx +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { - useCallback, - useState, - useEffect, - type ComponentProps, - type ReactNode, - type ReactElement, -} from "react"; -import { useHistory, useLocation } from "@docusaurus/router"; -import { toggleListItem } from "@site/src/utils/jsUtils"; -import type { TagType } from "@site/src/data-home/users"; - -import { prepareUserState } from "../../index"; -import styles from "./styles.module.css"; - -interface Props extends ComponentProps<"input"> { - icon: ReactElement>; - label: ReactNode; - tag: TagType; -} - -const TagQueryStringKey = "tags"; - -export function readSearchTags(search: string): TagType[] { - return new URLSearchParams(search).getAll(TagQueryStringKey) as TagType[]; -} - -function replaceSearchTags(search: string, newTags: TagType[]) { - const searchParams = new URLSearchParams(search); - searchParams.delete(TagQueryStringKey); - newTags.forEach((tag) => searchParams.append(TagQueryStringKey, tag)); - return searchParams.toString(); -} - -function ShowcaseTagSelect( - { id, icon, label, tag, ...rest }: Props, - ref: React.ForwardedRef -) { - const location = useLocation(); - const history = useHistory(); - const [selected, setSelected] = useState(false); - useEffect(() => { - const tags = readSearchTags(location.search); - setSelected(tags.includes(tag)); - }, [tag, location]); - const toggleTag = useCallback(() => { - const tags = readSearchTags(location.search); - const newTags = toggleListItem(tags, tag); - const newSearch = replaceSearchTags(location.search, newTags); - history.push({ - ...location, - search: newSearch, - state: prepareUserState(), - }); - }, [tag, location, history]); - return ( - <> - { - if (e.key === "Enter") { - toggleTag(); - } - }} - onFocus={(e) => { - if (e.relatedTarget) { - e.target.nextElementSibling?.dispatchEvent( - new KeyboardEvent("focus") - ); - } - }} - onBlur={(e) => { - e.target.nextElementSibling?.dispatchEvent(new KeyboardEvent("blur")); - }} - onChange={toggleTag} - checked={selected} - {...rest} - /> - - - ); -} - -export default React.forwardRef(ShowcaseTagSelect); diff --git a/src/pages/home/_components/ShowcaseTagSelect/styles.module.css b/src/pages/home/_components/ShowcaseTagSelect/styles.module.css deleted file mode 100644 index 6655781684..0000000000 --- a/src/pages/home/_components/ShowcaseTagSelect/styles.module.css +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -.checkboxLabel:hover { - opacity: 1; - box-shadow: 0 0 2px 1px var(--ifm-color-secondary-darkest); -} - -input[type="checkbox"] + .checkboxLabel { - display: flex; - align-items: center; - cursor: pointer; - line-height: 1.5; - border-radius: 4px; - padding: 0.275rem 0.8rem; - opacity: 0.85; - transition: opacity 200ms ease-out; - border: 2px solid var(--ifm-color-secondary-darkest); -} - -input:focus-visible + .checkboxLabel { - outline: 2px solid currentColor; -} - -input:checked + .checkboxLabel { - opacity: 0.9; - background-color: var(--site-color-checkbox-checked-bg); - border: 2px solid var(--ifm-color-primary-darkest); -} - -input:checked + .checkboxLabel:hover { - opacity: 0.75; - box-shadow: 0 0 2px 1px var(--ifm-color-primary-dark); -} diff --git a/src/pages/home/_components/ShowcaseTooltip/index.tsx b/src/pages/home/_components/ShowcaseTooltip/index.tsx deleted file mode 100644 index 3d431505f7..0000000000 --- a/src/pages/home/_components/ShowcaseTooltip/index.tsx +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useEffect, useState, useRef } from "react"; -import ReactDOM from "react-dom"; -import { usePopper } from "react-popper"; -import styles from "./styles.module.css"; - -interface Props { - anchorEl?: HTMLElement | string; - id: string; - text: string; - children: React.ReactElement; -} - -export default function Tooltip({ - children, - id, - anchorEl, - text, -}: Props): JSX.Element { - const [open, setOpen] = useState(false); - const [referenceElement, setReferenceElement] = useState( - null - ); - const [popperElement, setPopperElement] = useState(null); - const [arrowElement, setArrowElement] = useState(null); - const [container, setContainer] = useState(null); - const { styles: popperStyles, attributes } = usePopper( - referenceElement, - popperElement, - { - modifiers: [ - { - name: "arrow", - options: { - element: arrowElement, - }, - }, - { - name: "offset", - options: { - offset: [0, 8], - }, - }, - ], - } - ); - - const timeout = useRef(null); - const tooltipId = `${id}_tooltip`; - - useEffect(() => { - if (anchorEl) { - if (typeof anchorEl === "string") { - setContainer(document.querySelector(anchorEl)); - } else { - setContainer(anchorEl); - } - } else { - setContainer(document.body); - } - }, [container, anchorEl]); - - useEffect(() => { - const showEvents = ["mouseenter", "focus"]; - const hideEvents = ["mouseleave", "blur"]; - - const handleOpen = () => { - // There is no point in displaying an empty tooltip. - if (text === "") { - return; - } - - // Remove the title ahead of time to avoid displaying - // two tooltips at the same time (native + this one). - referenceElement?.removeAttribute("title"); - - timeout.current = window.setTimeout(() => { - setOpen(true); - }, 400); - }; - - const handleClose = () => { - clearInterval(timeout.current!); - setOpen(false); - }; - - if (referenceElement) { - showEvents.forEach((event) => { - referenceElement.addEventListener(event, handleOpen); - }); - - hideEvents.forEach((event) => { - referenceElement.addEventListener(event, handleClose); - }); - } - - return () => { - if (referenceElement) { - showEvents.forEach((event) => { - referenceElement.removeEventListener(event, handleOpen); - }); - - hideEvents.forEach((event) => { - referenceElement.removeEventListener(event, handleClose); - }); - } - }; - }, [referenceElement, text]); - - return ( - <> - {React.cloneElement(children, { - ref: setReferenceElement, - "aria-describedby": open ? tooltipId : undefined, - })} - {container - ? ReactDOM.createPortal( - open && ( - - ), - container - ) - : container} - - ); -} diff --git a/src/pages/home/_components/ShowcaseTooltip/styles.module.css b/src/pages/home/_components/ShowcaseTooltip/styles.module.css deleted file mode 100644 index 9fddba81fb..0000000000 --- a/src/pages/home/_components/ShowcaseTooltip/styles.module.css +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -.tooltip { - border-radius: 4px; - padding: 4px 8px; - color: var(--site-color-tooltip); - background: var(--site-color-tooltip-background); - font-size: 0.8rem; - z-index: 500; - line-height: 1.4; - font-weight: 500; - max-width: 300px; - opacity: 0.92; -} - -.tooltipArrow { - visibility: hidden; -} - -.tooltipArrow, -.tooltipArrow::before { - position: absolute; - width: 8px; - height: 8px; - background: inherit; -} - -.tooltipArrow::before { - visibility: visible; - content: ""; - transform: rotate(45deg); -} - -.tooltip[data-popper-placement^="top"] > .tooltipArrow { - bottom: -4px; -} - -.tooltip[data-popper-placement^="bottom"] > .tooltipArrow { - top: -4px; -} diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx deleted file mode 100644 index 5cf57f272d..0000000000 --- a/src/pages/home/index.tsx +++ /dev/null @@ -1,422 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment"; -import { useHistory, useLocation } from "@docusaurus/router"; -import { usePluralForm } from "@docusaurus/theme-common"; -import Translate, { translate } from "@docusaurus/Translate"; -import clsx from "clsx"; -import React, { useEffect, useMemo, useState } from "react"; - -import FavoriteIcon from "@site/src/components/svgIcons/FavoriteIcon"; -import { - sortedUsers, - TagList, - Tags, - type TagType, - type User, -} from "@site/src/data-home/users"; -import Layout from "@theme/Layout"; -import ShowcaseCard from "./_components/ShowcaseCard"; -import ShowcaseFilterToggle, { - readOperator, - type Operator, -} from "./_components/ShowcaseFilterToggle"; -import ShowcaseTagSelect, { - readSearchTags, -} from "./_components/ShowcaseTagSelect"; -import ShowcaseTooltip from "./_components/ShowcaseTooltip"; - -import styles from "./styles.module.css"; - -const TITLE = translate({ message: "Celo Documentation" }); -const DESCRIPTION = translate({ - message: - "Build decentralized applications that create the conditions for prosperity — for everyone.", -}); -const EDIT_URL = "general"; - -type UserState = { - scrollTopPosition: number; - focusedElementId: string | undefined; -}; - -function restoreUserState(userState: UserState | null) { - const { scrollTopPosition, focusedElementId } = userState ?? { - scrollTopPosition: 0, - focusedElementId: undefined, - }; - document.getElementById(focusedElementId)?.focus(); - window.scrollTo({ top: scrollTopPosition }); -} - -export function prepareUserState(): UserState | undefined { - if (ExecutionEnvironment.canUseDOM) { - return { - scrollTopPosition: window.scrollY, - focusedElementId: document.activeElement?.id, - }; - } - - return undefined; -} - -const SearchNameQueryKey = "name"; - -function readSearchName(search: string) { - return new URLSearchParams(search).get(SearchNameQueryKey); -} - -function filterUsers( - users: User[], - selectedTags: TagType[], - operator: Operator, - searchName: string | null -) { - if (searchName) { - // eslint-disable-next-line no-param-reassign - users = users.filter((user) => - user.title.toLowerCase().includes(searchName.toLowerCase()) - ); - } - if (selectedTags.length === 0) { - return users; - } - return users.filter((user) => { - if (user.tags.length === 0) { - return false; - } - if (operator === "AND") { - return selectedTags.every((tag) => user.tags.includes(tag)); - } - return selectedTags.some((tag) => user.tags.includes(tag)); - }); -} - -function useFilteredUsers() { - const location = useLocation(); - const [operator, setOperator] = useState("OR"); - // On SSR / first mount (hydration) no tag is selected - const [selectedTags, setSelectedTags] = useState([]); - const [searchName, setSearchName] = useState(null); - // Sync tags from QS to state (delayed on purpose to avoid SSR/Client - // hydration mismatch) - useEffect(() => { - setSelectedTags(readSearchTags(location.search)); - setOperator(readOperator(location.search)); - setSearchName(readSearchName(location.search)); - restoreUserState(location.state); - }, [location]); - - return useMemo( - () => filterUsers(sortedUsers, selectedTags, operator, searchName), - [selectedTags, operator, searchName] - ); -} - -function ShowcaseHeader() { - return ( -
    -

    {TITLE}

    -

    {DESCRIPTION}

    - - 🚀 Get started with Celo - -
    - ); -} - -function useSiteCountPlural() { - const { selectMessage } = usePluralForm(); - return (sitesCount: number) => - selectMessage( - sitesCount, - translate( - { - id: "showcase.filters.resultCount", - description: - 'Pluralized label for the number of sites found on the showcase. Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)', - message: "1 site|{sitesCount} sites", - }, - { sitesCount } - ) - ); -} - -function ShowcaseFilters() { - const filteredUsers = useFilteredUsers(); - const siteCountPlural = useSiteCountPlural(); - return ( -
    -
    -
    -

    - Filters -

    - {siteCountPlural(filteredUsers.length)} -
    - -
    -
      - {TagList.map((tag, i) => { - const { label, description, color } = Tags[tag]; - const id = `showcase_checkbox_id_${tag}`; - - return ( -
    • - - - ) : ( - - ) - } - /> - -
    • - ); - })} -
    -
    - ); -} - -const favoriteUsers = sortedUsers.filter((user) => - user.tags.includes("favorite") -); -const developers = sortedUsers.filter((user) => - user.tags.includes("developers") -); -const integrations = sortedUsers.filter((user) => - user.tags.includes("integrations") -); -const validators = sortedUsers.filter((user) => - user.tags.includes("validators") -); - -// const otherUsers = sortedUsers.filter( -// (user) => !user.tags.includes('favorite'), -// ); - -function SearchBar() { - const history = useHistory(); - const location = useLocation(); - const [value, setValue] = useState(null); - useEffect(() => { - setValue(readSearchName(location.search)); - }, [location]); - return ( -
    - { - setValue(e.currentTarget.value); - const newSearch = new URLSearchParams(location.search); - newSearch.delete(SearchNameQueryKey); - if (e.currentTarget.value) { - newSearch.set(SearchNameQueryKey, e.currentTarget.value); - } - history.push({ - ...location, - search: newSearch.toString(), - state: prepareUserState(), - }); - setTimeout(() => { - document.getElementById("searchbar")?.focus(); - }, 0); - }} - /> -
    - ); -} - -function ShowcaseCards() { - const filteredUsers = useFilteredUsers(); - - if (filteredUsers.length === 0) { - return ( -
    -
    -

    - No result -

    - -
    -
    - ); - } - - return ( -
    - {filteredUsers.length === sortedUsers.length ? ( - <> - {/* Get Started with Celo */} -
    -
    -
    -

    - Getting started -

    - {/* */} - {/* */} -
    -
      - {favoriteUsers.map((user) => ( - - ))} -
    -
    -
    - - {/* Developers */} -
    -
    -
    -

    - Developers -

    - {/* */} - {/* */} -
    -
      - {developers.map((user) => ( - - ))} -
    -
    -
    - {/* Developers */} - - {/* Integrations */} -
    -
    -
    -

    - Integrations -

    -
    -
      - {integrations.map((user) => ( - - ))} -
    -
    -
    - {/* Integrations */} - - {/* Validators */} -
    -
    -
    -

    - Validators -

    -
    -
      - {validators.map((user) => ( - - ))} -
    -
    -
    - {/* Validators */} - -
    - {/*

    - All sites -

    -
      - {otherUsers.map((user) => ( - - ))} -
    */} -
    - - ) : ( -
    -
    - -
    - {/*
      - {filteredUsers.map((user) => ( - - ))} -
    */} -
    - )} -
    - ); -} - -export default function Showcase(): JSX.Element { - return ( - -
    - - {/* */} - -
    -
    - ); -} diff --git a/src/pages/home/styles.module.css b/src/pages/home/styles.module.css deleted file mode 100644 index d9cfd94b04..0000000000 --- a/src/pages/home/styles.module.css +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -.filterCheckbox { - justify-content: space-between; -} - -.filterCheckbox, -.checkboxList { - display: flex; - align-items: center; -} - -.filterCheckbox > div:first-child { - display: flex; - flex: 1 1 auto; - align-items: center; -} - -.filterCheckbox > div > * { - margin-bottom: 0; - margin-right: 8px; -} - -.checkboxList { - flex-wrap: wrap; -} - -.checkboxListItem { - user-select: none; - white-space: nowrap; - height: 32px; - font-size: 0.8rem; - margin-top: 0.5rem; - margin-right: 0.5rem; -} - -.checkboxListItem:last-child { - margin-right: 0; -} - -.searchContainer { - margin-left: auto; -} - -.searchContainer input { - height: 30px; - border-radius: 15px; - padding: 10px; - border: 1px solid gray; -} - -.showcaseList { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 24px; -} - -.showcaseFavorite { - padding-top: 2rem; - padding-bottom: 2rem; - background-color: var(--site-color-favorite-background); -} - -.showcaseFavoriteHeader { - display: flex; - align-items: center; -} - -.showcaseFavoriteHeader > h2 { - margin-bottom: 0; -} - -.showcaseFavoriteHeader > svg { - width: 30px; - height: 30px; -} - -.svgIconFavoriteXs, -.svgIconFavorite { - color: var(--site-color-svg-icon-favorite); -} - -.svgIconFavoriteXs { - margin-left: 0.625rem; - font-size: 1rem; -} - -.svgIconFavorite { - margin-left: 1rem; -} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 0a473e14ad..2b586b5a7f 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,3 +1,12 @@ +import "./index.module.css"; + +import React, { useEffect } from "react"; + +import { Button } from "../components/Homepage/Button"; +import DevResources from "../components/Homepage/DevResources"; +import DiscoverSection from "../components/Homepage/DiscoverSection"; +import ExploreSection from "../components/Homepage/ExploreSection"; +import Footer from "../components/Homepage/Footer"; /** * Copyright (c) Facebook, Inc. and its affiliates. * @@ -6,13 +15,10 @@ */ import Head from "@docusaurus/Head"; import Link from "@docusaurus/Link"; -import Translate, { translate } from "@docusaurus/Translate"; +import { translate } from "@docusaurus/Translate"; import Layout from "@theme/Layout"; -import "./index.module.css"; - -import React, { useEffect } from "react"; import { useLocation } from "react-router-dom"; -import HeroImage from "../components/HeroImage"; +import StartBuilding from "../components/Homepage/StartBuilding"; const TITLE = translate({ message: "Celo Documentation" }); const DESCRIPTION = translate({ @@ -57,698 +63,42 @@ export default function HomePage(): JSX.Element { content="https://github.com/celo-org/docs/blob/main/static/img/preview.png?raw=true" /> -
    -
    -
    - - Celo L1 to Ethereum L2 Migration Coming Soon! - - - Learn More - - - - -
    -
    - +
    + {/* Hero Section */} +
    +

    + Build for the Real World on Celo +

    +

    + Create mobile-first decentralized applications accessible to + everyone, everywhere. +

    +
    + +
    -
    -
    - - Learn How to Build with Celo - -
    -
    -
    -
    - - - Quickstart with Celo Composer - - - {buildKnowMoreButton("/developer/deploy")} -
    -
    - -
    -
    -
    -
    - - - Build on MiniPay - - - {buildKnowMoreButton("/developer/build-on-minipay/overview")} -
    -
    - {/* biome-ignore lint/a11y/useAltText: */} - -
    -
    -
    -
    - - {/* Section 2 */} -
    - - - Explore Developer Tools and Resources - - -
    - - - Faucet - - - - Fund your Testnet Account. - - - - - - - - - - - Celo Scan - - - - - Explore transactions on Celo Network. - - - - - - - - - - Celo Bridge - - - - - How to bridge assets accross chains. - - - - - - - - - - Wallets - - - - Overview of ecosystem wallets. - - - - - - - - - - - Celo Libraries & SDKs - - - - - Search our vast range of libraries and SDKs. - - - - - - - - - - Deploy - - - - How to build and deploy a dApp. - - - - - - -
    -
    - - {/* Section 3 */} - {/*
    -
    - - Explore Providers and Frameworks - -
    - -
    */} - - {/* Section 4 */} - {/*
    - - Start Your Journey - -
    - - - Faucet - - - - Fund your Testnet Account. - - - - - - - - Celo Scan - - - - - Explore transactions on Celo Network. - - - - - - - Celo Bridge - - - - - How to bridge assets accross chains. - - - - - - - Wallets - - - - Overview of ecosystem wallets. - - - - - - - - Celo Libraries & SDKs - - - - - Search our vast range of libraries and SDKs. - - - - - - - Deploy - - - - How to build and deploy a dApp. - - - -
    -
    */} - - {/* section 5 */} - -
    -
    - - Browse our Docs by Category - -
    -
    -
    -
    - - Understanding Celo - -
    - {/* item 1 */} - {sectionFourCard( - translate({ id: "home.section4.understanding.whatIs.title" }), - translate({ - id: "home.section4.understanding.whatIs.description", - }), - "img/homepage/icons/WhatIsCelo_White.svg", - "/general", - )} + {/* Discover Section */} + - {sectionFourCard( - translate({ - id: "home.section4.understanding.architecture.title", - }), - translate({ - id: "home.section4.understanding.architecture.description", - }), - "img/homepage/icons/Architechture_White.svg", - "/general/architecture", - )} + {/* Explore Section */} + - {sectionFourCard( - translate({ - id: "home.section4.understanding.whitepapers.title", - }), - translate({ - id: "home.section4.understanding.whitepapers.description", - }), - "img/homepage/icons/WhitePapers_white.svg", - "/general/whitepapers", - )} + {/* Start Building Section */} + - {sectionFourCard( - translate({ id: "home.section4.understanding.protocol.title" }), - translate({ - id: "home.section4.understanding.protocol.description", - }), - "img/homepage/icons/Protocol_White.svg", - "/protocol", - )} -
    - - {/* item 2 */} - -
    -
    - - Developer Tools - -
    - {sectionFourCard( - translate({ id: "home.section4.developer.contractKit.title" }), - translate({ - id: "home.section4.developer.contractKit.description", - }), - "img/homepage/icons/ContractKit_White.svg", - "/developer/contractkit", - )} - - {sectionFourCard( - translate({ - id: "home.section4.developer.rainbowKitCelo.title", - }), - translate({ - id: "home.section4.developer.rainbowKitCelo.description", - }), - "img/homepage/icons/Rainbow_White.svg", - "/developer/rainbowkit-celo", - )} - - {sectionFourCard( - translate({ id: "home.section4.developer.celoCli.title" }), - translate({ - id: "home.section4.developer.celoCli.description", - }), - "img/homepage/icons/CLI_White.svg", - "/cli", - )} -
    - -
    -
    - Build with Celo -
    - {sectionFourCard( - translate({ id: "home.section4.build.celoComposer.title" }), - translate({ - id: "home.section4.build.celoComposer.description", - }), - "img/homepage/icons/CeloComposer_White.svg", - "developer/deploy", - )} - - {sectionFourCard( - translate({ id: "home.section4.build.migrate.title" }), - translate({ id: "home.section4.build.migrate.description" }), - "img/homepage/icons/Migration_White.svg", - "/developer/migrate/from-ethereum", - )} - - {sectionFourCard( - translate({ id: "home.section4.build.oracles.title" }), - translate({ id: "home.section4.build.oracles.description" }), - "img/homepage/icons/Oracle_White.svg", - "/protocol/oracle", - )} - - {sectionFourCard( - translate({ id: "home.section4.build.architecture.title" }), - translate({ - id: "home.section4.build.architecture.description", - }), - "img/homepage/icons/NewToWeb3_White.svg", - "/general/web2-to-web3", - )} -
    - -
    -
    - Validators -
    - {sectionFourCard( - translate({ id: "home.section4.validators.run.title" }), - translate({ id: "home.section4.validators.run.description" }), - "img/homepage/icons/Validator_White.svg", - "/validator", - )} - - {sectionFourCard( - translate({ id: "home.section4.validators.node.title" }), - translate({ id: "home.section4.validators.node.description" }), - "img/homepage/icons/Node_White.svg", - "/validator/security", - )} -
    -
    -
    - - {/* section 5 end */} - - {/* section 6 */} - -
    -
    - - Join the Builder Ecosystem - -
    -
    - - Discover the many ways to connect with our growing community of - developers. - -
    -
    -
    -
    - - Sign Up for Developer Updates - - {buildKnowMoreButton( - "https://events.celo.org/builders" - )} -
    -
    -
    - -
    -
    - {sectionFourCard( - "Connect with the Community", - "Join our Discord", - "img/homepage/connect.svg", - "https://discord.com/invite/celo" - )} - {sectionFourCard( - "Bring Your Ideas to Life", - "Sign up for upcoming hackathons", - "img/homepage/contribute.svg", - "https://lemonade.social/celo" - )} - - {sectionFourCard( - "Apply for Grants", - "Explore public goods funding programs", - "img/homepage/ambassador.svg", - "https://www.celopg.eco/programs" - )} - - {sectionFourCard( - "Access Exclusive Resources", - "Register as an active Celo builder", - "img/homepage/connect.svg", - "https://forms.gle/yDQUYGZS3BYR8WFZA" - )} -
    -
    -
    - - {/*
    -
    - Join Our Ecosystem -
    -
    -
    -
    - - - Receive Funding to Build Your Blockchain Projects - - - {buildKnowMoreButton("/community/grant-playbook")} -
    -
    -
    - -
    -
    - {sectionFourCard( - "Celo dApp Launch Checklist", - "A comprehensive guide to assist you in launching dapps on Celo.", - "img/doc-images/logos/connect.svg", - "/developer/launch-checklist", - )} - {sectionFourCard( - translate({ id: "home.section6.contribute.title" }), - translate({ id: "home.section6.contribute.description" }), - "img/doc-images/logos/contribute.svg", - "/community/guidelines", - )} - - {sectionFourCard( - translate({ id: "home.section6.ambassadors.title" }), - translate({ id: "home.section6.ambassadors.description" }), - "img/doc-images/logos/ambassador.svg", - "https://celocommunity.xyz/join-the-ambassador-program", - )} - - {sectionFourCard( - translate({ id: "home.section6.connect.title" }), - translate({ id: "home.section6.connect.description" }), - "img/doc-images/logos/connect.svg", - "https://celo.org/community", - )} -
    -
    -
    */} + {/* Dev Resources Section */} + - {/* section 6 end */} + {/* Footer */} +
    ); diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000000..a5ef193506 --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/static/blog/using-thirdweb-insight-on-celo.png b/static/blog/using-thirdweb-insight-on-celo.png new file mode 100644 index 0000000000..404b2af0cc Binary files /dev/null and b/static/blog/using-thirdweb-insight-on-celo.png differ diff --git a/static/fonts/advercase-bold.woff2 b/static/fonts/advercase-bold.woff2 new file mode 100644 index 0000000000..ba33814bb2 Binary files /dev/null and b/static/fonts/advercase-bold.woff2 differ diff --git a/static/fonts/advercase-regular.woff2 b/static/fonts/advercase-regular.woff2 new file mode 100644 index 0000000000..e0701241be Binary files /dev/null and b/static/fonts/advercase-regular.woff2 differ diff --git a/static/img/build-for-minipay.png b/static/img/build-for-minipay.png new file mode 100644 index 0000000000..1d032c690d Binary files /dev/null and b/static/img/build-for-minipay.png differ diff --git a/static/img/self-protocol.png b/static/img/self-protocol.png new file mode 100644 index 0000000000..12fccb0a18 Binary files /dev/null and b/static/img/self-protocol.png differ diff --git a/static/img/smart-phone.png b/static/img/smart-phone.png new file mode 100644 index 0000000000..811ede5e25 Binary files /dev/null and b/static/img/smart-phone.png differ diff --git a/static/img/tap-into-stables.png b/static/img/tap-into-stables.png new file mode 100644 index 0000000000..15635fc7a5 Binary files /dev/null and b/static/img/tap-into-stables.png differ diff --git a/tailwind.config.js b/tailwind.config.js index 23b0c6721f..2d82f8c4ba 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,4 +1,6 @@ // tailwind.config.js +const { fontFamily } = require("tailwindcss/defaultTheme"); + /** @type {import('tailwindcss').Config} */ module.exports = { corePlugins: { @@ -29,6 +31,9 @@ module.exports = { lotus: "#FFA3EB", lavender: "#B490FF", }, + fontFamily: { + advercase: ["Advercase", ...fontFamily.sans], + }, }, }, plugins: [ diff --git a/yarn.lock b/yarn.lock index fa4cdbc41f..caa3c43fa5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5101,6 +5101,13 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.4" safe-buffer "^5.2.1" +class-variance-authority@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz#4008a798a0e4553a781a57ac5177c9fb5d043787" + integrity sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg== + dependencies: + clsx "^2.1.1" + clean-css@^5.2.2, clean-css@^5.3.2, clean-css@~5.3.2: version "5.3.3" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd" @@ -5141,7 +5148,7 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" -clsx@^2.0.0, clsx@^2.1.0: +clsx@^2.0.0, clsx@^2.1.0, clsx@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==