diff --git a/.gitignore b/.gitignore index cb33574d61..4e25d86efc 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ yarn-error.log* # vercel .vercel + +# others +build.log diff --git a/README.md b/README.md index cb054a7687..2955c1f1e7 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,4 @@ You can start editing the page by modifying `pages/index.js`. The page auto-upda ## Adding your RPC -If you wish to add your RPC, please follow the [PR template](https://github.com/DefiLlama/chainlist/blob/main/pull_request_template.md) +If you wish to add your RPC, please follow this [PR template](https://github.com/DefiLlama/chainlist/blob/main/pull_request_template.md) diff --git a/components/AdBanner/index.js b/components/AdBanner/index.js new file mode 100755 index 0000000000..fce3d6a1a2 --- /dev/null +++ b/components/AdBanner/index.js @@ -0,0 +1,155 @@ +import { useCallback, useEffect, useRef, useState } from "react"; +import { Native } from "@hypelab/sdk-react"; +import { HYPELAB_NATIVE_PLACEMENT_SLUG } from "../../constants/hypelab"; + +export const AdBanner = () => { + const [isSquare, setIsSquare] = useState(false); + const [hideNativeTextContent, setHideNativeTextContent] = useState(true); + const resizeObserver = useRef(null); + + const imageRef = useCallback((node) => { + if (node) resizeObserver.current?.observe(node); + }, []); + + useEffect(() => { + resizeObserver.current = new ResizeObserver((entries) => { + for (const entry of entries) { + if (entry.contentRect.width > 0 && entry.contentRect.height > 0) { + setIsSquare(entry.contentRect.width == entry.contentRect.height); + setHideNativeTextContent(entry.contentRect.height > 220); + } + } + }); + }, [setIsSquare, setHideNativeTextContent]); + + return ( + +
+
+
+ +
+
+ + +
+
+
+
+
+
+ ); +}; + +const NativeTextContent = ({ hidden }) => { + const containerRef = useRef(null); + const [width, setWidth] = useState(0); + + useEffect(() => { + const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + setWidth(entry.contentRect.width); + } + }); + + const container = containerRef.current; + + if (container) { + resizeObserver.observe(container); + } + + return () => { + if (container) { + resizeObserver.unobserve(container); + } + }; + }, [containerRef]); + + return ( +
+ +
+
+ +
+
+ +
+
+
+ ); +}; + +const AdvertiserIcon = ({ small = false }) => { + return ( +
+ + icon + +
+ ); +}; + +const AdvertiserName = ({ small = false }) => { + return ( +
+ + + +
+ ); +}; + +const AdvertiserCta = ({ ad, small = false }) => { + return ( +
+ +
+
+
+ ); +}; + +const NativeLink = ({ children }) => { + return ( + + {children} + + ); +}; + +const HypeLabOverlay = () => { + const iconStyle = { + width: "18px", + height: "18px", + backgroundSize: "15px 15px", + backgroundPosition: "center", + backgroundRepeat: "no-repeat", + backgroundImage: `url('data:image/svg+xml,')`, + }; + + return ( +
+
+
Ads by HypeLab
+
+ ); +}; diff --git a/components/Layout/index.js b/components/Layout/index.js index a8f7063c55..da803dbcbe 100644 --- a/components/Layout/index.js +++ b/components/Layout/index.js @@ -1,11 +1,34 @@ import * as React from "react"; +import { useEffect } from "react"; import Header from "../header"; // import { useTranslations } from "next-intl"; import { notTranslation as useTranslations } from "../../utils"; import Logo from "./Logo"; import { useRouter } from "next/router"; +const toggleTheme = (e) => { + e.preventDefault(); + const element = document.body; + document.getElementById("theme-toggle-dark-icon").classList.toggle("hidden"); + document.getElementById("theme-toggle-light-icon").classList.toggle("hidden"); + const result = element.classList.toggle("dark"); + localStorage.setItem("theme", result ? "dark" : "light"); +}; + +const initTheme = () => { + const element = document.body; + if (element.classList.contains("dark")) { + document.getElementById("theme-toggle-light-icon").classList.remove("hidden"); + } else { + document.getElementById("theme-toggle-dark-icon").classList.remove("hidden"); + } +}; + export default function Layout({ children, lang }) { + useEffect(() => { + initTheme(); + }, []); + const t = useTranslations("Common", lang); const router = useRouter(); @@ -16,7 +39,7 @@ export default function Layout({ children, lang }) { return (
-
+
@@ -27,7 +50,7 @@ export default function Layout({ children, lang }) {
-
-
+
+
{children}
diff --git a/components/RPCList/index.js b/components/RPCList/index.js index 451bb1a5d3..7bdedc196b 100644 --- a/components/RPCList/index.js +++ b/components/RPCList/index.js @@ -1,15 +1,15 @@ import { useEffect, useMemo, useState } from "react"; import * as Fathom from "fathom-client"; -// import { useTranslations } from "next-intl"; import { notTranslation as useTranslations } from "../../utils"; import useRPCData from "../../hooks/useRPCData"; import useAddToNetwork from "../../hooks/useAddToNetwork"; -import { useClipboard } from "../../hooks/useClipboard"; import { useLlamaNodesRpcData } from "../../hooks/useLlamaNodesRpcData"; import { FATHOM_DROPDOWN_EVENTS_ID } from "../../hooks/useAnalytics"; -import { useAccount, useRpcStore } from "../../stores"; +import { useRpcStore } from "../../stores"; import { renderProviderText } from "../../utils"; import { Tooltip } from "../../components/Tooltip"; +import useAccount from "../../hooks/useAccount"; +import { Popover, PopoverDisclosure, usePopoverStore } from "@ariakit/react/popover"; export default function RPCList({ chain, lang }) { const [sortChains, setSorting] = useState(true); @@ -58,7 +58,7 @@ export default function RPCList({ chain, lang }) { let trust = "transparent"; let disableConnect = false; - if (!height || !latency || topRpc.height - height > 3 || topRpc.latency - latency > 5000) { + if (!height || !latency || topRpc.height - height > 3 || latency - topRpc.latency > 5000) { trust = "red"; } else if (topRpc.height - height < 2 && topRpc.latency - latency > -600) { trust = "green"; @@ -79,30 +79,13 @@ export default function RPCList({ chain, lang }) { const { rpcData, hasLlamaNodesRpc } = useLlamaNodesRpcData(chain.chainId, data); - const isEthMainnet = chain?.name === "Ethereum Mainnet"; - return ( -
- {isEthMainnet && ( -

- Follow{" "} - - this guide - {" "} - to change RPC endpoint's of Ethereum Mainnet -

- )} - - +
+
{rpcData.map((item, index) => { - let className = 'bg-inherit'; + let className = "bg-inherit"; if (hasLlamaNodesRpc && index === 0) { - className = 'bg-[#F9F9F9]'; + className = "dark:bg-[#0D0D0D] bg-[#F9F9F9]"; } return ( - ) + ); })}
{`${chain.name} RPC URL List`}
@@ -161,7 +143,7 @@ export default function RPCList({ chain, lang }) { } const Shimmer = () => { - return
; + return
; }; function PrivacyIcon({ tracking, isOpenSource = false }) { @@ -181,13 +163,12 @@ function PrivacyIcon({ tracking, isOpenSource = false }) { return ; } -const Row = ({ values, chain, isEthMainnet, privacy, lang, className }) => { +const Row = ({ values, chain, privacy, lang, className }) => { const t = useTranslations("Common", lang); const { data, isLoading, refetch } = values; const rpcs = useRpcStore((state) => state.rpcs); const addRpc = useRpcStore((state) => state.addRpc); - const account = useAccount((state) => state.account); useEffect(() => { // ignore first request to a url and refetch to calculate latency which doesn't include DNS lookup @@ -205,8 +186,8 @@ const Row = ({ values, chain, isEthMainnet, privacy, lang, className }) => { return ( - - {isLoading ? : data?.url} + + {isLoading ? : data?.url ? : null} {isLoading ? : data?.height} {isLoading ? : data?.latency} @@ -225,27 +206,23 @@ const Row = ({ values, chain, isEthMainnet, privacy, lang, className }) => { )} - - - {isLoading ? : } - - + + + {isLoading ? : } + + {isLoading ? ( ) : ( <> - {isEthMainnet ? ( - - ) : ( - !data.disableConnect && ( - - ) + {!data.disableConnect && ( + )} )} @@ -254,32 +231,11 @@ const Row = ({ values, chain, isEthMainnet, privacy, lang, className }) => { ); }; -const CopyUrl = ({ url = "" }) => { - const { hasCopied, onCopy } = useClipboard() - - const handleCopy = () => { - if (url.includes("eth.llamarpc")) { - Fathom.trackGoal(FATHOM_DROPDOWN_EVENTS_ID[1], 0); - } - - return onCopy(url) - } - - return ( - - ); -}; - const EmptyIcon = () => ( - + -) +); const RedIcon = () => ( @@ -320,3 +276,53 @@ const LightGreenIcon = () => ( /> ); + +const CopyUrl = ({ url }) => { + const [open, setOpen] = useState(false); + + useEffect(() => { + if (open) { + setTimeout(() => { + setOpen(false); + }, 500); + } + }, [open]); + + const popover = usePopoverStore({ placement: "bottom", open }); + + return ( + <> + { + navigator.clipboard.writeText(url).then( + () => { + setOpen(true); + if (url.includes("eth.llamarpc")) { + Fathom.trackGoal(FATHOM_DROPDOWN_EVENTS_ID[1], 0); + } + }, + () => { + console.error(`Failed to copy ${url}`); + }, + ); + }} + > + {url} + + } + /> + {popover.show ? ( + +

Copied!

+
+ ) : null} + + ); +}; diff --git a/components/Tooltip/index.js b/components/Tooltip/index.js index ea6d31040a..ee290b6951 100755 --- a/components/Tooltip/index.js +++ b/components/Tooltip/index.js @@ -1,25 +1,34 @@ -import { Tooltip as AriaTooltip, TooltipAnchor, useTooltipState } from 'ariakit/tooltip'; +import Linkify from "react-linkify"; +import { Tooltip as AriaTooltip, TooltipAnchor, useTooltipStore } from "@ariakit/react/tooltip"; export const Tooltip = ({ children, content, ...props }) => { - const tooltip = useTooltipState({ placement: 'bottom' }); + const tooltip = useTooltipStore({ placement: "bottom", showTimeout: 100 }); if (!content) return {children}; return ( <> {children} - {content} + ( + + {decoratedText} + + )} + > + {content} + ); diff --git a/components/chain/index.js b/components/chain/index.js index 10701ca9af..2cc1578267 100644 --- a/components/chain/index.js +++ b/components/chain/index.js @@ -44,7 +44,7 @@ export default function Chain({ chain, buttonOnly, lang }) { if (buttonOnly) { return (