From d0b95231f6e09573ea03157f20052a1932ae5d6f Mon Sep 17 00:00:00 2001 From: Joro Date: Tue, 6 Aug 2024 10:58:09 +0300 Subject: [PATCH 1/4] Announcement bar - use dynamic content --- docusaurus.config.js | 6 +- src/theme/AnnouncementBar/Content/index.js | 71 +++++++++++++++++++--- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/docusaurus.config.js b/docusaurus.config.js index be47d6cd..af135b8d 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -215,7 +215,7 @@ const config = { announcementBar: { id: "mainnet", content: - 'Cartesi Rollups is Mainnet Ready! Over 1M in CTSI is up for grabs... if you can hack Cartesi Rollups.', + 'Cartesi Rollups is Mainnet Ready! Over 1M in CTSI is up for grabs...{{varName}} AND {{varName2}} if you can hack Cartesi Rollups.', backgroundColor: "rgba(0, 0, 0, 0.7)", textColor: "#FFFFFF", @@ -374,8 +374,8 @@ const config = { from: "/cartesi-rollups/", }, { - to:"/cartesi-rollups/1.3/", - from:"/cartesi-rollups/overview" + to: "/cartesi-rollups/1.3/", + from: "/cartesi-rollups/overview", }, { to: "/cartesi-machine/", diff --git a/src/theme/AnnouncementBar/Content/index.js b/src/theme/AnnouncementBar/Content/index.js index a7a8b61b..dbaa76ba 100644 --- a/src/theme/AnnouncementBar/Content/index.js +++ b/src/theme/AnnouncementBar/Content/index.js @@ -1,17 +1,74 @@ -import React from 'react'; -import clsx from 'clsx'; -import {useThemeConfig} from '@docusaurus/theme-common'; -import styles from './styles.module.css'; +import React, { useEffect, useMemo, useState } from "react"; +import clsx from "clsx"; +import { useThemeConfig } from "@docusaurus/theme-common"; +import styles from "./styles.module.css"; export default function AnnouncementBarContent(props) { - const {announcementBar} = useThemeConfig(); - const {content} = announcementBar; + const { announcementBar } = useThemeConfig(); + const { content } = announcementBar; + + const [dynamicContent, setDynamicContent] = useState(content); + + // Fetch data for variables in the content + const varNameFetcher = async () => { + const response = await fetch( + "https://jsonplaceholder.typicode.com/todos/1" + ); + const data = await response.json(); + return data.title; + }; + + const varNameFetcher2 = async () => { + const response = await fetch( + "https://jsonplaceholder.typicode.com/todos/2" + ); + const data = await response.json(); + return data.title; + }; + + // Add all variables and fetchers here + const fetchMap = { + varName: varNameFetcher(), + varName2: varNameFetcher2(), + }; + + // Extract variables from the content + const contentVars = useMemo(() => { + return content.match(/{{(.*?)}}/g)?.map((v) => v.slice(2, -2)); + }, [content]); + + // Update the content with the fetched values + useEffect(() => { + if (!contentVars) { + return; + } + + function fetchVars() { + return Promise.all( + contentVars.map((contentVar) => { + return fetchMap[contentVar]; + }) + ); + } + + async function updateContent() { + const values = await fetchVars(); + let newContent = content; + contentVars.forEach((v, i) => { + newContent = newContent.replace(`{{${v}}}`, values[i]); + }); + setDynamicContent(newContent); + } + + updateContent(); + }, [contentVars]); + return (
); } From 0459a2a828c1d6ee0013d73de7cae9c5356422ee Mon Sep 17 00:00:00 2001 From: Dimitar Angelkov Date: Wed, 7 Aug 2024 23:05:51 +0300 Subject: [PATCH 2/4] mainnet data fetching --- docusaurus.config.js | 3 +- package.json | 3 +- .../Content/contracts/contracts.ts | 291 ++++++++++++++++++ src/theme/AnnouncementBar/Content/index.js | 47 ++- yarn.lock | 125 +++++++- 5 files changed, 445 insertions(+), 24 deletions(-) create mode 100644 src/theme/AnnouncementBar/Content/contracts/contracts.ts diff --git a/docusaurus.config.js b/docusaurus.config.js index af135b8d..d9038cc0 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -215,8 +215,7 @@ const config = { announcementBar: { id: "mainnet", content: - 'Cartesi Rollups is Mainnet Ready! Over 1M in CTSI is up for grabs...{{varName}} AND {{varName2}} if you can hack Cartesi Rollups.', - + 'Cartesi Rollups is Mainnet Ready! {{balance}} in {{symbol}} is up for grabs... if you can hack Cartesi Rollups.', backgroundColor: "rgba(0, 0, 0, 0.7)", textColor: "#FFFFFF", isCloseable: true, diff --git a/package.json b/package.json index 1f527362..89c4dc4c 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "react-dom": "^17.0.1", "react-tooltip": "^5.21.4", "sass": "^1.72.0", - "tailwindcss": "^3.1.7" + "tailwindcss": "^3.1.7", + "viem": "^2.19.1" }, "browserslist": { "production": [ diff --git a/src/theme/AnnouncementBar/Content/contracts/contracts.ts b/src/theme/AnnouncementBar/Content/contracts/contracts.ts new file mode 100644 index 00000000..d4ca46ac --- /dev/null +++ b/src/theme/AnnouncementBar/Content/contracts/contracts.ts @@ -0,0 +1,291 @@ +export const wagmiContract = { + address: "0x491604c0FDF08347Dd1fa4Ee062a822A5DD06B5D" as `0x${string}`, + abi: [ + { + inputs: [ + { + internalType: "address", + name: "minter", + type: "address", + }, + { + internalType: "uint256", + name: "initialSupply", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "from", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "spender", + type: "address", + }, + ], + name: "allowance", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "approve", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "balanceOf", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [ + { + internalType: "uint8", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "subtractedValue", + type: "uint256", + }, + ], + name: "decreaseAllowance", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "addedValue", + type: "uint256", + }, + ], + name: "increaseAllowance", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "transfer", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address", + }, + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "transferFrom", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + ], +} as const; diff --git a/src/theme/AnnouncementBar/Content/index.js b/src/theme/AnnouncementBar/Content/index.js index dbaa76ba..3769c6b3 100644 --- a/src/theme/AnnouncementBar/Content/index.js +++ b/src/theme/AnnouncementBar/Content/index.js @@ -2,33 +2,46 @@ import React, { useEffect, useMemo, useState } from "react"; import clsx from "clsx"; import { useThemeConfig } from "@docusaurus/theme-common"; import styles from "./styles.module.css"; + +import { http, createPublicClient } from "viem"; +import { mainnet } from "viem/chains"; +import { formatEther } from "viem"; +import { wagmiContract } from "./contracts/contracts"; + +const transport = http( + "https://eth-mainnet.g.alchemy.com/v2/cBxzBgf91hVaZIV-gnC0kuc-K1WGd2xX" +); +const symbol = "CTSI"; +const defaultBalance = 0; +const defaultFrom = 0; + +const client = createPublicClient({ + chain: mainnet, + transport, +}); + export default function AnnouncementBarContent(props) { const { announcementBar } = useThemeConfig(); const { content } = announcementBar; const [dynamicContent, setDynamicContent] = useState(content); + const [balanceLoaded, setBalanceLoaded] = useState(false); // Fetch data for variables in the content - const varNameFetcher = async () => { - const response = await fetch( - "https://jsonplaceholder.typicode.com/todos/1" - ); - const data = await response.json(); - return data.title; - }; - - const varNameFetcher2 = async () => { - const response = await fetch( - "https://jsonplaceholder.typicode.com/todos/2" - ); - const data = await response.json(); - return data.title; + const getBalance = async () => { + const contractRead = await client.readContract({ + ...wagmiContract, + functionName: "balanceOf", + args: ["0x0974CC873dF893B302f6be7ecf4F9D4b1A15C366"], + }); + setBalanceLoaded(true); + return new Intl.NumberFormat().format(parseInt(formatEther(contractRead))); }; // Add all variables and fetchers here const fetchMap = { - varName: varNameFetcher(), - varName2: varNameFetcher2(), + balance: getBalance(), + symbol: symbol, }; // Extract variables from the content @@ -60,7 +73,7 @@ export default function AnnouncementBarContent(props) { } updateContent(); - }, [contentVars]); + }, [contentVars, balanceLoaded]); return (
Date: Thu, 8 Aug 2024 08:30:39 +0300 Subject: [PATCH 3/4] Update index.js --- src/theme/AnnouncementBar/Content/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/theme/AnnouncementBar/Content/index.js b/src/theme/AnnouncementBar/Content/index.js index 3769c6b3..c1a21cff 100644 --- a/src/theme/AnnouncementBar/Content/index.js +++ b/src/theme/AnnouncementBar/Content/index.js @@ -12,8 +12,6 @@ const transport = http( "https://eth-mainnet.g.alchemy.com/v2/cBxzBgf91hVaZIV-gnC0kuc-K1WGd2xX" ); const symbol = "CTSI"; -const defaultBalance = 0; -const defaultFrom = 0; const client = createPublicClient({ chain: mainnet, From 99ed84b89e741634ee6a91a361a77396c3b7953b Mon Sep 17 00:00:00 2001 From: Joro Date: Thu, 8 Aug 2024 08:58:48 +0300 Subject: [PATCH 4/4] fix announcement bar loading --- src/theme/AnnouncementBar/Content/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/theme/AnnouncementBar/Content/index.js b/src/theme/AnnouncementBar/Content/index.js index c1a21cff..b8963e21 100644 --- a/src/theme/AnnouncementBar/Content/index.js +++ b/src/theme/AnnouncementBar/Content/index.js @@ -22,6 +22,7 @@ export default function AnnouncementBarContent(props) { const { announcementBar } = useThemeConfig(); const { content } = announcementBar; + const [loaded, setLoaded] = useState(false); const [dynamicContent, setDynamicContent] = useState(content); const [balanceLoaded, setBalanceLoaded] = useState(false); @@ -68,6 +69,7 @@ export default function AnnouncementBarContent(props) { newContent = newContent.replace(`{{${v}}}`, values[i]); }); setDynamicContent(newContent); + setLoaded(true); } updateContent(); @@ -79,7 +81,9 @@ export default function AnnouncementBarContent(props) { className={clsx(styles.content, props.className)} // Developer provided the HTML, so assume it's safe. // eslint-disable-next-line react/no-danger - dangerouslySetInnerHTML={{ __html: dynamicContent }} + dangerouslySetInnerHTML={{ + __html: loaded ? dynamicContent : null, + }} /> ); }