diff --git a/.vscode/settings.json b/.vscode/settings.json
index f7f353781..dc01eae78 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -9,5 +9,9 @@
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
- "editor.defaultFormatter": "esbenp.prettier-vscode"
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "[json]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "typescript.preferences.importModuleSpecifier": "non-relative",
}
diff --git a/apps/web/app/(entity)/[network]/[...path]/page.tsx b/apps/web/app/(entity)/[network]/[...path]/page.tsx
index 0d53b6a51..7e348e690 100644
--- a/apps/web/app/(entity)/[network]/[...path]/page.tsx
+++ b/apps/web/app/(entity)/[network]/[...path]/page.tsx
@@ -32,10 +32,24 @@ export async function generateMetadata({
const query = params.path[1];
return {
title: `Searching for ${query}`,
+ icons: [
+ {
+ rel: "icon",
+ url: `/api/og?model=favicon&networkSlug=${network.slug}`,
+ },
+ ],
};
}
- return getMetadata(params, network);
+ return {
+ ...getMetadata(params, network),
+ icons: [
+ {
+ rel: "icon",
+ url: `/api/og?model=favicon&networkSlug=${network.slug}`,
+ },
+ ],
+ };
}
export default function EntityPage({
diff --git a/apps/web/app/(entity)/[network]/error.tsx b/apps/web/app/(entity)/[network]/error.tsx
index b3cd23172..f3ab0d28b 100644
--- a/apps/web/app/(entity)/[network]/error.tsx
+++ b/apps/web/app/(entity)/[network]/error.tsx
@@ -6,11 +6,11 @@ import { ErrorBox } from "~/ui/error/box";
import { Footer } from "~/ui/footer";
import { HomeBg } from "~/ui/home-bg";
import { HomeBgMobile } from "~/ui/home-bg/mobile";
-import { useSearchOptionsContext } from "~/ui/search-options-context";
+import { useGroupedNetworksContext } from "~/ui/grouped-networks-context";
export default function Error() {
const params = useParams();
- const optionGroups = useSearchOptionsContext();
+ const optionGroups = useGroupedNetworksContext();
const network = React.useMemo(() => {
const values = optionGroups.flat();
return (
diff --git a/apps/web/app/(entity)/[network]/layout.tsx b/apps/web/app/(entity)/[network]/layout.tsx
index 761eb6107..21d8027b7 100644
--- a/apps/web/app/(entity)/[network]/layout.tsx
+++ b/apps/web/app/(entity)/[network]/layout.tsx
@@ -1,5 +1,5 @@
// components
-import { Header } from "~/ui/header";
+import { EntityHeader } from "~/ui/entity-header";
import { HideBodyOverflow } from "~/ui/hide-body-overflow";
// utils
@@ -30,7 +30,7 @@ export default async function BlockLayout({
>
-
+
;
@@ -34,38 +52,504 @@ export async function generateMetadata(props: Props): Promise
{
},
],
},
+ icons: [
+ {
+ rel: "icon",
+ url: `/api/og?model=favicon&networkSlug=${network.slug}`,
+ },
+ ],
};
}
-export default async function NetworkWidgetPage({ params }: Props) {
+export default async function NetworkPage({ params }: Props) {
const network = await getSingleNetwork(params.network);
// this fixes a bug on vercel with build where it would throw if the network doesn't
// exist (even though technically it should always exist)
if (!network) notFound();
+ return (
+ <>
+
+
+
+ >
+ );
+}
+
+type FeaturedChains = Exclude<
+ SingleNetwork["config"]["featuredChains"],
+ undefined
+>;
+function FeaturedChains({
+ chainsLeft,
+ chainsRight,
+}: {
+ chainsLeft: FeaturedChains;
+ chainsRight: FeaturedChains;
+}) {
+ const noOfMissingChainsLeft = 3 - chainsLeft.length;
+ const noOfMissingChainsRight = 3 - chainsRight.length;
+ return (
+ <>
+
+
+
+
+ {chainsLeft.slice(0, 3).map((chain, index) => (
+
+
+
+
+
+ ))}
+ {range(1, noOfMissingChainsLeft).map((index) => (
+
+ ))}
+
+
+
+
+
+
+ {chainsRight.slice(0, 3).map((chain, index) => (
+
+
+
+
+
+ ))}
+
+ {range(1, noOfMissingChainsRight).map((index) => (
+
+ ))}
+
+ >
+ );
+}
+
+function HeroSection({ network }: { network: SingleNetwork }) {
+ const links = network.config.links;
+ const featuredChains = network.config.featuredChains ?? [];
+ const indexOfSplit = Math.ceil(featuredChains.length / 2);
+ const [chainsLeft, chainsRight] = [
+ featuredChains.slice(0, indexOfSplit),
+ featuredChains.slice(indexOfSplit),
+ ];
+ return (
+
+ {network.brand === "eclipse" && (
+ <>
+
+
+ >
+ )}
+ {network.config.platform === "dymension" && (
+ <>
+
+
+ >
+ )}
+ {network.brand === "celestia" && featuredChains.length > 0 && (
+
+ )}
+ {network.brand === "dymension" && featuredChains.length > 0 && (
+
+ )}
+
+
+
+ {/* Logo */}
+
+
+ {/* network type pill */}
+
+ {network.config.layer}
+
+
+ {/* Big text (network name) */}
+
+
+ {network.brand}
+
+ {network.config.platform === "dymension" ? (
+ <>
+
+ {network.config.platform}
+ >
+ ) : (
+ {network.chainName}
+ )}
+
+
+
+ {network.config.description}
+
+
+ {/* Links */}
+ {links.length > 0 && (
+
+
+
+
+ {links.map((link) => (
+
+
+ {link.type === "website" && (
+
+ )}
+ {link.type === "x" && (
+
+ )}
+ {link.type === "discord" && (
+
+ )}
+ {link.type === "github" && (
+
+ )}
+
+
+ ))}
+
+
+
+
+ )}
+
+ {/* Badges */}
+
+ {network.paidVersion && (
+
+ Verified on
+
+ Modular Cloud
+
+ )}
+
+ {network.config.badges.map((badge) => (
+
+ {badge.relation} on
+ {badge.logoURL && (
+
+ )}
+ {capitalize(badge.target)}
+
+ ))}
+
+
+ );
+}
+
+function NetworkSections({ network }: { network: SingleNetwork }) {
+ if (network.config.platform === "dymension") {
+ return (
+
+
+ {network.config.ecosystems.map((ecosystem) => (
+
+ ))}
+
+
+ );
+ }
switch (network.config.widgetLayout) {
case "SVM":
return (
-
+
);
case "Celestia":
return (
-
+
);
case "Dymension":
- return ;
+ return (
+
+ );
default:
return null;
}
}
+function SectionHeading(props: { title: string; shortcut: string }) {
+ return (
+
+
+
+ {props.title}
+
+
+
+
+ );
+}
+
export async function generateStaticParams() {
const paidNetworks = await getAllPaidNetworks();
return paidNetworks.map((network) => ({ network: network.slug }));
diff --git a/apps/web/app/(home)/[network]/scroll-to-section.tsx b/apps/web/app/(home)/[network]/scroll-to-section.tsx
new file mode 100644
index 000000000..188d20379
--- /dev/null
+++ b/apps/web/app/(home)/[network]/scroll-to-section.tsx
@@ -0,0 +1,34 @@
+"use client";
+
+import { useHotkey } from "~/lib/hooks/use-hotkey";
+
+export function ScrollToSection() {
+ useHotkey({
+ keys: ["a", "A"],
+ listener: () => {
+ const section = document.getElementById("activity");
+ if (section) {
+ section.scrollIntoView({
+ behavior: "smooth",
+ block: "start",
+ });
+ }
+ return true;
+ },
+ });
+ useHotkey({
+ keys: ["s", "S"],
+ listener: () => {
+ const section = document.getElementById("statistics");
+
+ if (section) {
+ section.scrollIntoView({
+ behavior: "smooth",
+ block: "start",
+ });
+ }
+ return true;
+ },
+ });
+ return null;
+}
diff --git a/apps/web/app/(home)/layout.tsx b/apps/web/app/(home)/layout.tsx
index e715f7d2a..7cf90459c 100644
--- a/apps/web/app/(home)/layout.tsx
+++ b/apps/web/app/(home)/layout.tsx
@@ -1,26 +1,25 @@
+import { HomeBg } from "~/ui/home-bg";
+import { HomeBgMobile } from "~/ui/home-bg/mobile";
import { Footer } from "~/ui/footer";
-import { SearchForm } from "~/ui/search/search-form";
+import { Header } from "~/ui/header";
export default async function HomeLayout({
children,
- logo,
}: {
- logo: React.ReactNode;
children: React.ReactNode;
}) {
return (
-
-
-
-
+
+
+
+
+
+ {children}
{/*
diff --git a/apps/web/app/api/og/components/favicon.tsx b/apps/web/app/api/og/components/favicon.tsx
new file mode 100644
index 000000000..d36d7d0f0
--- /dev/null
+++ b/apps/web/app/api/og/components/favicon.tsx
@@ -0,0 +1,23 @@
+import { MCLogo } from "~/ui/mc-logo";
+
+export type FaviconProps = {
+ networkBrandGradient: string;
+};
+
+export function Favicon({ networkBrandGradient }: FaviconProps) {
+ return (
+
+
+
+ );
+}
diff --git a/apps/web/app/api/og/components/opengraph-home.tsx b/apps/web/app/api/og/components/opengraph-home.tsx
index fc1e8f8b3..57fe872af 100644
--- a/apps/web/app/api/og/components/opengraph-home.tsx
+++ b/apps/web/app/api/og/components/opengraph-home.tsx
@@ -1,16 +1,13 @@
/* eslint-disable @next/next/no-img-element */
import { OG_SIZE } from "~/lib/constants";
-import { getSingleNetwork } from "~/lib/network";
+import type { SingleNetwork } from "~/lib/fetch-networks";
+import { MCLogo } from "~/ui/mc-logo";
export type OpenGraphHomeProps = {
- networkSlug: string;
+ network: SingleNetwork;
};
-export async function OpenGraphHome({ networkSlug }: OpenGraphHomeProps) {
- const network = await getSingleNetwork(networkSlug);
-
- if (!network) return null;
-
+export function OpenGraphHome({ network }: OpenGraphHomeProps) {
const primaryColor = `hsl(${network.config.primaryColor})`;
return (
) {
- return (
-
- );
-}
-
function OGGrid(props: React.SVGProps
& { tw?: string }) {
return (
);
});
diff --git a/apps/web/ui/grouped-networks-context/index.tsx b/apps/web/ui/grouped-networks-context/index.tsx
new file mode 100644
index 000000000..f342edafa
--- /dev/null
+++ b/apps/web/ui/grouped-networks-context/index.tsx
@@ -0,0 +1,29 @@
+"use client";
+
+import * as React from "react";
+import type { GroupedNetworkChains } from "~/lib/grouped-network-chains";
+
+interface Props {
+ children: React.ReactNode;
+ value: GroupedNetworkChains;
+}
+
+export function GroupedNetworksProvider({ children, value }: Props) {
+ return (
+
+ {children}
+
+ );
+}
+
+const GroupedNetworksContext = React.createContext(
+ null,
+);
+
+export function useGroupedNetworksContext() {
+ const contextValue = React.use(GroupedNetworksContext);
+ if (!contextValue) {
+ throw new Error("Should provide the value of the network chains");
+ }
+ return contextValue;
+}
diff --git a/apps/web/ui/header-tabs/index.tsx b/apps/web/ui/header-tabs/index.tsx
index d1038d9db..b06b9c934 100644
--- a/apps/web/ui/header-tabs/index.tsx
+++ b/apps/web/ui/header-tabs/index.tsx
@@ -65,9 +65,7 @@ export async function HeaderTabs({ params }: Props) {
const { tabs: resolvedTabs } = page;
- // TODO: we should use this schema directly without modification
const tabs: Tab[] = resolvedTabs.map((tab) => {
- // TODO: We should have a map of icons for each type of tab
let Icon =
tab.text.toLowerCase() === "transactions" ||
tab.text.toLowerCase() === "latest transactions"
diff --git a/apps/web/ui/header/branded-logo.tsx b/apps/web/ui/header/branded-logo.tsx
new file mode 100644
index 000000000..0a4645950
--- /dev/null
+++ b/apps/web/ui/header/branded-logo.tsx
@@ -0,0 +1,42 @@
+"use client";
+import * as React from "react";
+
+import { MCLogo } from "~/ui/mc-logo";
+import Link from "next/link";
+import Image from "next/image";
+import { getBrandSVGLogoSRC } from "~/lib/shared-utils";
+import { Heart } from "~/ui/icons";
+import { useCurrentNetwork } from "~/lib/hooks/use-current-network";
+
+export function BrandedLogo() {
+ const network = useCurrentNetwork();
+
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/ui/header/header-search-button.tsx b/apps/web/ui/header/header-search-button.tsx
index c49eafd55..66f501972 100644
--- a/apps/web/ui/header/header-search-button.tsx
+++ b/apps/web/ui/header/header-search-button.tsx
@@ -1,59 +1,35 @@
"use client";
+
import * as React from "react";
-// components
+import { useParams } from "next/navigation";
+import { HeadlessRoute } from "~/lib/headless-utils";
import { SearchModal } from "~/ui/search/search-modal";
+import { useGroupedNetworksContext } from "~/ui/grouped-networks-context";
import { ArrowRight, Search } from "~/ui/icons";
-import Image from "next/image";
import { Button } from "~/ui/button";
-
-// utils
-import { useParams, usePathname } from "next/navigation";
import { cn } from "~/ui/shadcn/utils";
-import { capitalize, truncateHash } from "~/lib/shared-utils";
-
-// types
-import type { HeadlessRoute } from "~/lib/headless-utils";
-import type { GroupedNetworkChains } from "~/lib/grouped-network-chains";
-interface Props {
- optionGroups: GroupedNetworkChains;
-}
-export function HeaderSearchButton({ optionGroups }: Props) {
- const routeParams = useParams() as HeadlessRoute;
- const pathname = usePathname();
+type Props = {
+ children: React.ReactNode;
+ className?: string;
+};
- const params: HeadlessRoute = {
- ...routeParams,
- path: pathname
- .replace(`/${routeParams.network}`, "")
- .split("/")
- .filter(Boolean),
- };
+export function HeaderSearchButton({ children, className }: Props) {
+ const params = useParams() as Pick;
+ const allNetworks = useGroupedNetworksContext();
const network = React.useMemo(() => {
- const values = Object.values(optionGroups).flat();
+ const values = Object.values(allNetworks).flat();
return (
values.find((network) => network.slug === params.network) ?? values[0]
);
- }, [optionGroups, params.network]);
-
- let entityType = capitalize(params.path[0]);
- let query = "";
- if (params.path.length > 1) {
- if (entityType === "Addresses") {
- entityType = "Address";
- } else if (entityType.endsWith("s")) {
- entityType = entityType.substring(0, entityType.length - 1);
- }
- query = decodeURIComponent(params.path[1]);
- }
+ }, [allNetworks, params.network]);
return (
-
-
-
- {/* Network logo, name & chainName */}
-
-
-
-
- {capitalize(network.brandName)}
- /
- {capitalize(network.displayName)}
-
-
+
+
-
-
- {/* Query */}
-
- {entityType}
- {/* For accessibility */}
-
- {entityType} {query}
-
-
- {/* bigger screens */}
-
- {query ? truncateHash(query, 25) : ""}
-
-
-
+
+ {children}
+
+
-
-
- {/* eslint-disable-next-line @next/next/no-img-element */}
-

-
-
Modular Cloud
-
-
-
-
- {/* Bigger screens */}
-
+
);
}
diff --git a/apps/web/ui/header/network-status-badge.tsx b/apps/web/ui/header/network-status-badge.tsx
new file mode 100644
index 000000000..35a0650fb
--- /dev/null
+++ b/apps/web/ui/header/network-status-badge.tsx
@@ -0,0 +1,73 @@
+"use client";
+
+import * as React from "react";
+import { useParams } from "next/navigation";
+import type { HeadlessRoute } from "~/lib/headless-utils";
+import { useNetworkStatus } from "~/ui/search/use-network-status";
+import { cn } from "~/ui/shadcn/utils";
+import { useCurrentNetwork } from "~/lib/hooks/use-current-network";
+import { FancyShieldCheck } from "~/ui/icons";
+
+export function NetworkStatusBadge() {
+ const params = useParams() as Pick
;
+ const currentNetwork = useCurrentNetwork();
+ const { data } = useNetworkStatus(params.network);
+
+ if (!data) {
+ return (
+
+ Fetching network status...
+
+ );
+ }
+
+ const isPremiumChain = currentNetwork.verified;
+ const isNetworkHealthy = data[params.network].healthy;
+
+ return (
+
+ {isNetworkHealthy ? (
+
+ {isPremiumChain ? (
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+ ) : isPremiumChain ? (
+
+ ) : (
+
+ )}
+
+ Network {isNetworkHealthy ? "Online" : "Unavailable"}
+
+
+ );
+}
diff --git a/apps/web/ui/icon-svgs/ArrowBottomRight.svg b/apps/web/ui/icon-svgs/ArrowBottomRight.svg
new file mode 100644
index 000000000..cbdcb32c9
--- /dev/null
+++ b/apps/web/ui/icon-svgs/ArrowBottomRight.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/web/ui/icon-svgs/ArrowTopRight.svg b/apps/web/ui/icon-svgs/ArrowTopRight.svg
new file mode 100644
index 000000000..63078d092
--- /dev/null
+++ b/apps/web/ui/icon-svgs/ArrowTopRight.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/web/ui/icon-svgs/DiscordLogo.svg b/apps/web/ui/icon-svgs/DiscordLogo.svg
new file mode 100644
index 000000000..3741c8157
--- /dev/null
+++ b/apps/web/ui/icon-svgs/DiscordLogo.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/web/ui/icon-svgs/FancyShield.svg b/apps/web/ui/icon-svgs/FancyShieldCheck.svg
similarity index 100%
rename from apps/web/ui/icon-svgs/FancyShield.svg
rename to apps/web/ui/icon-svgs/FancyShieldCheck.svg
diff --git a/apps/web/ui/icon-svgs/FancyShieldCross.svg b/apps/web/ui/icon-svgs/FancyShieldCross.svg
new file mode 100644
index 000000000..b4e565216
--- /dev/null
+++ b/apps/web/ui/icon-svgs/FancyShieldCross.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/web/ui/icon-svgs/Heart.svg b/apps/web/ui/icon-svgs/Heart.svg
new file mode 100644
index 000000000..0844f9390
--- /dev/null
+++ b/apps/web/ui/icon-svgs/Heart.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/web/ui/icon-svgs/TiltedGlobe.svg b/apps/web/ui/icon-svgs/TiltedGlobe.svg
new file mode 100644
index 000000000..8cf1880ec
--- /dev/null
+++ b/apps/web/ui/icon-svgs/TiltedGlobe.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/web/ui/icon-svgs/Trends.svg b/apps/web/ui/icon-svgs/Trends.svg
new file mode 100644
index 000000000..d7c855675
--- /dev/null
+++ b/apps/web/ui/icon-svgs/Trends.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/web/ui/icon-svgs/XIcon.svg b/apps/web/ui/icon-svgs/XIcon.svg
new file mode 100644
index 000000000..40331ffec
--- /dev/null
+++ b/apps/web/ui/icon-svgs/XIcon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/apps/web/ui/icon-svgs/XLogo.svg b/apps/web/ui/icon-svgs/XLogo.svg
new file mode 100644
index 000000000..96bc2d16f
--- /dev/null
+++ b/apps/web/ui/icon-svgs/XLogo.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/web/ui/icons/ArrowBottomRight.tsx b/apps/web/ui/icons/ArrowBottomRight.tsx
new file mode 100644
index 000000000..e019ec533
--- /dev/null
+++ b/apps/web/ui/icons/ArrowBottomRight.tsx
@@ -0,0 +1,19 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgArrowBottomRight = (props: SVGProps) => (
+
+
+
+);
+export default SvgArrowBottomRight;
diff --git a/apps/web/ui/icons/ArrowTopRight.tsx b/apps/web/ui/icons/ArrowTopRight.tsx
new file mode 100644
index 000000000..3cb25df99
--- /dev/null
+++ b/apps/web/ui/icons/ArrowTopRight.tsx
@@ -0,0 +1,19 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgArrowTopRight = (props: SVGProps) => (
+
+
+
+);
+export default SvgArrowTopRight;
diff --git a/apps/web/ui/icons/DiscordLogo.tsx b/apps/web/ui/icons/DiscordLogo.tsx
new file mode 100644
index 000000000..9e8593334
--- /dev/null
+++ b/apps/web/ui/icons/DiscordLogo.tsx
@@ -0,0 +1,16 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgDiscordLogo = (props: SVGProps) => (
+
+
+
+);
+export default SvgDiscordLogo;
diff --git a/apps/web/ui/icons/FancyShield.tsx b/apps/web/ui/icons/FancyShieldCheck.tsx
similarity index 75%
rename from apps/web/ui/icons/FancyShield.tsx
rename to apps/web/ui/icons/FancyShieldCheck.tsx
index 03607e0ae..62ad14cfe 100644
--- a/apps/web/ui/icons/FancyShield.tsx
+++ b/apps/web/ui/icons/FancyShieldCheck.tsx
@@ -1,26 +1,29 @@
import * as React from "react";
import type { SVGProps } from "react";
-const SvgFancyShield = (props: SVGProps) => (
+const SvgFancyShieldCheck = (props: SVGProps) => (
-
+
-
+
) => (
);
-export default SvgFancyShield;
+export default SvgFancyShieldCheck;
diff --git a/apps/web/ui/icons/FancyShieldCross.tsx b/apps/web/ui/icons/FancyShieldCross.tsx
new file mode 100644
index 000000000..02b6c6dd8
--- /dev/null
+++ b/apps/web/ui/icons/FancyShieldCross.tsx
@@ -0,0 +1,18 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgFancyShieldCross = (props: SVGProps) => (
+
+
+
+);
+export default SvgFancyShieldCross;
diff --git a/apps/web/ui/icons/Heart.tsx b/apps/web/ui/icons/Heart.tsx
new file mode 100644
index 000000000..c374a4a9f
--- /dev/null
+++ b/apps/web/ui/icons/Heart.tsx
@@ -0,0 +1,16 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgHeart = (props: SVGProps) => (
+
+
+
+);
+export default SvgHeart;
diff --git a/apps/web/ui/icons/TiltedGlobe.tsx b/apps/web/ui/icons/TiltedGlobe.tsx
new file mode 100644
index 000000000..2a15d6d76
--- /dev/null
+++ b/apps/web/ui/icons/TiltedGlobe.tsx
@@ -0,0 +1,19 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgTiltedGlobe = (props: SVGProps) => (
+
+
+
+);
+export default SvgTiltedGlobe;
diff --git a/apps/web/ui/icons/Trends.tsx b/apps/web/ui/icons/Trends.tsx
new file mode 100644
index 000000000..659e18538
--- /dev/null
+++ b/apps/web/ui/icons/Trends.tsx
@@ -0,0 +1,19 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgTrends = (props: SVGProps) => (
+
+
+
+);
+export default SvgTrends;
diff --git a/apps/web/ui/icons/XIcon.tsx b/apps/web/ui/icons/XIcon.tsx
new file mode 100644
index 000000000..799feeefa
--- /dev/null
+++ b/apps/web/ui/icons/XIcon.tsx
@@ -0,0 +1,18 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgXIcon = (props: SVGProps) => (
+
+
+
+);
+export default SvgXIcon;
diff --git a/apps/web/ui/icons/XLogo.tsx b/apps/web/ui/icons/XLogo.tsx
new file mode 100644
index 000000000..3c5d315dd
--- /dev/null
+++ b/apps/web/ui/icons/XLogo.tsx
@@ -0,0 +1,16 @@
+import * as React from "react";
+import type { SVGProps } from "react";
+const SvgXLogo = (props: SVGProps) => (
+
+
+
+);
+export default SvgXLogo;
diff --git a/apps/web/ui/icons/index.ts b/apps/web/ui/icons/index.ts
index 5fc770cd0..64361678b 100644
--- a/apps/web/ui/icons/index.ts
+++ b/apps/web/ui/icons/index.ts
@@ -1,3 +1,4 @@
+export { default as ArrowBottomRight } from "./ArrowBottomRight";
export { default as ArrowDown } from "./ArrowDown";
export { default as ArrowLeftRight } from "./ArrowLeftRight";
export { default as ArrowOff } from "./ArrowOff";
@@ -5,6 +6,7 @@ export { default as ArrowOn } from "./ArrowOn";
export { default as ArrowOut } from "./ArrowOut";
export { default as ArrowRight } from "./ArrowRight";
export { default as ArrowRightGradient } from "./ArrowRightGradient";
+export { default as ArrowTopRight } from "./ArrowTopRight";
export { default as BarChart } from "./BarChart";
export { default as BellOff } from "./BellOff";
export { default as BellOn } from "./BellOn";
@@ -35,6 +37,7 @@ export { default as CornerUpRight } from "./CornerUpRight";
export { default as CubesOff } from "./CubesOff";
export { default as CubesOn } from "./CubesOn";
export { default as Disabled } from "./Disabled";
+export { default as DiscordLogo } from "./DiscordLogo";
export { default as Document } from "./Document";
export { default as Electricity } from "./Electricity";
export { default as ElipsHorizOff } from "./ElipsHorizOff";
@@ -45,7 +48,8 @@ export { default as Enveloppe } from "./Enveloppe";
export { default as EyeOff } from "./EyeOff";
export { default as EyeOn } from "./EyeOn";
export { default as FancyCheck } from "./FancyCheck";
-export { default as FancyShield } from "./FancyShield";
+export { default as FancyShieldCheck } from "./FancyShieldCheck";
+export { default as FancyShieldCross } from "./FancyShieldCross";
export { default as Filters } from "./Filters";
export { default as Folder } from "./Folder";
export { default as Gas } from "./Gas";
@@ -55,6 +59,7 @@ export { default as GlobeCyber } from "./GlobeCyber";
export { default as GlobeWeb } from "./GlobeWeb";
export { default as GreenTick } from "./GreenTick";
export { default as Grid } from "./Grid";
+export { default as Heart } from "./Heart";
export { default as Home } from "./Home";
export { default as Home2 } from "./Home2";
export { default as KeyboardArrowDown } from "./KeyboardArrowDown";
@@ -86,8 +91,12 @@ export { default as Spinner } from "./Spinner";
export { default as Stars } from "./Stars";
export { default as SunOff } from "./SunOff";
export { default as SunOn } from "./SunOn";
+export { default as TiltedGlobe } from "./TiltedGlobe";
+export { default as Trends } from "./Trends";
export { default as UsdCoin } from "./UsdCoin";
export { default as UserOff } from "./UserOff";
export { default as UserOn } from "./UserOn";
export { default as Warning } from "./Warning";
export { default as XCircle } from "./XCircle";
+export { default as XIcon } from "./XIcon";
+export { default as XLogo } from "./XLogo";
diff --git a/apps/web/ui/mc-logo/index.tsx b/apps/web/ui/mc-logo/index.tsx
new file mode 100644
index 000000000..44bd5da5f
--- /dev/null
+++ b/apps/web/ui/mc-logo/index.tsx
@@ -0,0 +1,20 @@
+export function MCLogo(props: React.SVGProps) {
+ return (
+
+
+
+ );
+}
diff --git a/apps/web/ui/network-widgets/layouts/celestia/celestia-widget-content.tsx b/apps/web/ui/network-widgets/layouts/celestia/celestia-widget-content.tsx
index 963c77450..87e5d746f 100644
--- a/apps/web/ui/network-widgets/layouts/celestia/celestia-widget-content.tsx
+++ b/apps/web/ui/network-widgets/layouts/celestia/celestia-widget-content.tsx
@@ -46,7 +46,7 @@ export function CelestiaWidgetLayoutContent({
const [apiResult, latestBlocks, latestTransactions] = data;
return (
-
+
{lastUpdatedTime && (