From d6da737d71a94f3ace00c90c80481db7fc3bc021 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 02:25:42 +0100 Subject: [PATCH 01/57] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20modify=20the=20da?= =?UTF-8?q?ta=20structure=20for=20integration=20chains?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/network.ts | 155 +++++++++++++++--- .../web/public/images/celestia-logo-white.svg | 3 + .../public/images/dymension-logo-white.svg | 3 + apps/web/public/images/eclipse-logo-white.svg | 10 ++ apps/web/this-is-ridiculous.ts | 152 +---------------- 5 files changed, 148 insertions(+), 175 deletions(-) create mode 100644 apps/web/public/images/celestia-logo-white.svg create mode 100644 apps/web/public/images/dymension-logo-white.svg create mode 100644 apps/web/public/images/eclipse-logo-white.svg diff --git a/apps/web/lib/network.ts b/apps/web/lib/network.ts index f36f70e37..dea8de42f 100644 --- a/apps/web/lib/network.ts +++ b/apps/web/lib/network.ts @@ -1,7 +1,6 @@ import "server-only"; import { z } from "zod"; import { env } from "~/env.mjs"; -import { CACHE_KEYS } from "./cache-keys"; import { cache } from "react"; import { integrations, integrationList } from "~/lib/cache"; @@ -32,6 +31,27 @@ export const singleNetworkSchema = z.object({ `linear-gradient(94deg, #6833FF 19.54%, #336CFF 75.56%, #33B6FF 93.7%)`, ), ecosystems: z.array(z.string()).optional().default([]), + description: z.string().optional(), + type: z.string().optional().default("Execution Layer"), + links: z + .array( + z.object({ + type: z.enum(["website", "github", "x", "discord"]), + href: z.string().url(), + }), + ) + .optional() + .default([]), + badges: z + .array( + z.object({ + relation: z.string().nonempty(), + target: z.string().nonempty(), + logoURL: z.string().url().optional(), + href: z.string().optional(), + }), + ) + .default([]), }), paidVersion: z.boolean(), slug: z.string(), @@ -59,11 +79,11 @@ export const getSingleNetwork = cache(async function getSingleNetwork( const found = integrations[slug].value; return singleNetworkSchema.parse(found); } catch (error) { - return await getSingleNetworkFetch(slug); + return await fetchSingleNetwork(slug); } }); -async function getSingleNetworkFetch(slug: string) { +export async function fetchSingleNetwork(slug: string) { const describeIntegrationBySlugAPISchema = z.object({ result: z.object({ integration: singleNetworkSchema, @@ -74,26 +94,14 @@ async function getSingleNetworkFetch(slug: string) { let integration: SingleNetwork | null = null; if (!integration) { - const date = new Date().getTime(); - console.time( - `[${date}] FETCH [${CACHE_KEYS.networks.single(slug).join(", ")}]`, - ); let { result } = await fetch( `${ env.INTERNAL_INTEGRATION_API_URL }/integrations/slug/${encodeURIComponent(slug)}`, - { - cache: "force-cache", - next: { - tags: CACHE_KEYS.networks.single(slug), - }, - }, ) .then((r) => r.json()) .then((data) => describeIntegrationBySlugAPISchema.parse(data)); - console.timeEnd( - `[${date}] FETCH [${CACHE_KEYS.networks.single(slug).join(", ")}]`, - ); + integration = result.integration; } @@ -101,19 +109,54 @@ async function getSingleNetworkFetch(slug: string) { if (integration.slug === "nautilus-mainnet") { integration.config.widgetLayout = "EvmWithPrice"; } - if (integration.slug === "eclipse-devnet") { - integration.config.widgetLayout = "SVM"; - integration.config.primaryColor = "236 15% 18%"; - integration.config.cssGradient = `linear-gradient(97deg, #000 -5.89%, #1E1E1E 83.12%, #000 103.23%)`; - } if (integration.brand === "celestia") { - integration.config.widgetLayout = "Celestia"; - integration.config.primaryColor = "256 100% 67%"; - integration.config.cssGradient = `linear-gradient(94deg, #6833FF 19.54%, #336CFF 75.56%, #33B6FF 93.7%)`; + integration.config = { + ...integration.config, + widgetLayout: "Celestia", + logoUrl: "/images/celestia-logo-white.svg", + primaryColor: "256.07 100% 67.06%", + cssGradient: `linear-gradient(89deg, #8457FF -17.52%, #501FD7 89.78%);`, + description: + "Celestia is a modular data availability network that securely scales with the number of users, making it easy for anyone to launch their own blockchain.", + links: [], + }; + } + if (integration.brand === "eclipse") { + integration.config = { + ...integration.config, + widgetLayout: "SVM", + logoUrl: "/images/eclipse-logo-white.svg", + primaryColor: "119.25 33.33% 52.94%", + cssGradient: `linear-gradient(180deg, #65BB64 0%, #569B55 99.99%, #000 100%);`, + description: + "Eclipse is Ethereum's fastest L2, powered by the Solana Virtual Machine.", + links: [], + badges: [ + { + relation: "Settlement", + target: "Sepolia", + logoURL: "/images/ethereum.png", + }, + { + relation: "DA", + target: "Mocha", + logoURL: "/images/celestia-logo-small.png", + href: "/celestia-mocha", + }, + ], + }; } if (integration.brand === "dymension") { - integration.config.widgetLayout = "Dymension"; - integration.config.primaryColor = "29 13% 45%"; + integration.config = { + ...integration.config, + widgetLayout: "Dymension", + logoUrl: "/images/dymension-logo-white.svg", + cssGradient: `linear-gradient(89deg, #24201F -17.52%, #24201F 89.78%);`, + primaryColor: "12 7.46% 13.14%", + description: + "Dymension is a home for easily deployable and lightning fast app-chains, called RollApps.", + links: [], + }; } return integration; @@ -122,6 +165,66 @@ async function getSingleNetworkFetch(slug: string) { } } +export async function fetchAllNetworks() { + let allIntegrations: Array = []; + + let nextToken: string | null = null; + + do { + const sp = new URLSearchParams({ + returnAll: "true", + maxResults: "1000", + nextToken: nextToken ?? "", + }); + const response = await fetch( + `${ + env.INTERNAL_INTEGRATION_API_URL + }/integrations-summary?${sp.toString()}`, + ).then(async (r) => { + const text = await r.text(); + const status = r.status; + if (status !== 200) { + console.log({ + res: text, + status: r.status, + statusText: r.statusText, + }); + } + return JSON.parse(text); + }); + + const integrationSummaryAPISchema = z.object({ + result: z + .object({ + integrations: z.array(singleNetworkSchema.nullable().catch(null)), + nextToken: z.string().nullish(), + }) + .nullish(), + }); + const { result } = integrationSummaryAPISchema.parse(response); + nextToken = result?.nextToken ?? null; + + if (result?.integrations) { + for (const integration of result.integrations) { + if (integration !== null) { + allIntegrations.push(integration); + } + } + } + } while (nextToken); + + return allIntegrations.sort((a, b) => { + // prioritize celestia before every other chain + if (a.brand === "celestia") return -1; + if (b.brand === "celestia") return 1; + + // put non paid chains at the end + if (!a.paidVersion) return 1; + if (!b.paidVersion) return -1; + return 0; + }); +} + export const getAllPaidNetworks = cache(async function getAllPaidNetworks() { const allNetworks = getAllNetworks(); return allNetworks.filter((network) => network.paidVersion).slice(0, 30); diff --git a/apps/web/public/images/celestia-logo-white.svg b/apps/web/public/images/celestia-logo-white.svg new file mode 100644 index 000000000..5740dac02 --- /dev/null +++ b/apps/web/public/images/celestia-logo-white.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/apps/web/public/images/dymension-logo-white.svg b/apps/web/public/images/dymension-logo-white.svg new file mode 100644 index 000000000..6df399548 --- /dev/null +++ b/apps/web/public/images/dymension-logo-white.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/apps/web/public/images/eclipse-logo-white.svg b/apps/web/public/images/eclipse-logo-white.svg new file mode 100644 index 000000000..197f9e9a7 --- /dev/null +++ b/apps/web/public/images/eclipse-logo-white.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/apps/web/this-is-ridiculous.ts b/apps/web/this-is-ridiculous.ts index 7ffb8be49..857dc056e 100644 --- a/apps/web/this-is-ridiculous.ts +++ b/apps/web/this-is-ridiculous.ts @@ -5,159 +5,13 @@ */ import fs from "node:fs/promises"; import { FileSystemCacheDEV } from "~/lib/fs-cache-dev"; -import { preprocess, z } from "zod"; import { capitalize } from "./lib/shared-utils"; -import { env } from "~/env.mjs"; +import { fetchSingleNetwork, fetchAllNetworks } from "./lib/network"; -export const singleNetworkSchema = z.object({ - config: z.object({ - logoUrl: z.string().url(), - rpcUrls: z.record( - z.enum(["evm", "cosmos", "svm", "celestia"]), - z.string().url(), - ), - token: z.object({ - name: z.string().max(128), - decimals: z.number(), - }), - platform: z.string().max(64).optional(), - // TODO : These are defaulted for now, but it should be returned by the API - widgetLayout: z - .enum(["EvmWithPrice", "EvmWithoutPrice", "SVM", "Celestia", "Dymension"]) - .optional() - .catch(undefined), - // This is in HSL format, and is used like this : hsl("224 94% 51%") - primaryColor: z.string().optional().default("256 100% 67%"), - cssGradient: z - .string() - .optional() - // this value is directly used as `background-image: linear-gradient(90deg, #0F4EF7 -10.76%, #00D5E2 98.22%);` - .default( - `linear-gradient(94deg, #6833FF 19.54%, #336CFF 75.56%, #33B6FF 93.7%)`, - ), - ecosystems: z.array(z.string()).optional().default([]), - }), - paidVersion: z.boolean(), - slug: z.string(), - chainName: z.string(), - brand: z.string(), - accountId: z.string(), - internalId: z.string(), - integrationId: z.string().uuid(), - createdTime: preprocess((arg) => new Date(arg as any), z.date()), -}); - -export type SingleNetwork = z.infer; - -const getAllNetworks = cache(async function getAllNetworks(): Promise< - Array -> { - let allIntegrations: Array = []; - - let nextToken: string | null = null; - - do { - const sp = new URLSearchParams({ - returnAll: "true", - maxResults: "1000", - nextToken: nextToken ?? "", - }); - const response = await fetch( - `${ - env.INTERNAL_INTEGRATION_API_URL - }/integrations-summary?${sp.toString()}`, - ).then(async (r) => { - const text = await r.text(); - const status = r.status; - if (status !== 200) { - console.log({ - res: text, - status: r.status, - statusText: r.statusText, - }); - } - return JSON.parse(text); - }); - - const integrationSummaryAPISchema = z.object({ - result: z - .object({ - integrations: z.array(singleNetworkSchema.nullable().catch(null)), - nextToken: z.string().nullish(), - }) - .nullish(), - }); - const { result } = integrationSummaryAPISchema.parse(response); - nextToken = result?.nextToken ?? null; - - if (result?.integrations) { - for (const integration of result.integrations) { - if (integration !== null) { - allIntegrations.push(integration); - } - } - } - } while (nextToken); - - return allIntegrations.sort((a, b) => { - // prioritize celestia before every other chain - if (a.brand === "celestia") return -1; - if (b.brand === "celestia") return 1; - - // put non paid chains at the end - if (!a.paidVersion) return 1; - if (!b.paidVersion) return -1; - return 0; - }); -}, "integration-summary"); +const getAllNetworks = cache(fetchAllNetworks, "integration-summary"); const getSingleNetwork = (slug: string) => - cache(async function getSingleNetwork(slug: string) { - const describeIntegrationBySlugAPISchema = z.object({ - result: z.object({ - integration: singleNetworkSchema, - }), - }); - - try { - let integration: SingleNetwork | null = null; - - if (!integration) { - let { result } = await fetch( - `${ - env.INTERNAL_INTEGRATION_API_URL - }/integrations/slug/${encodeURIComponent(slug)}`, - ) - .then((r) => r.json()) - .then((data) => describeIntegrationBySlugAPISchema.parse(data)); - - integration = result.integration; - } - - // FIXME : this is hardcoded because widgets are not supported yet on other networks other than these - if (integration.slug === "nautilus-mainnet") { - integration.config.widgetLayout = "EvmWithPrice"; - } - if (integration.slug === "eclipse-devnet") { - integration.config.widgetLayout = "SVM"; - integration.config.primaryColor = "236 15% 18%"; - integration.config.cssGradient = `linear-gradient(97deg, #000 -5.89%, #1E1E1E 83.12%, #000 103.23%)`; - } - if (integration.brand === "celestia") { - integration.config.widgetLayout = "Celestia"; - integration.config.primaryColor = "256 100% 67%"; - integration.config.cssGradient = `linear-gradient(94deg, #6833FF 19.54%, #336CFF 75.56%, #33B6FF 93.7%)`; - } - if (integration.brand === "dymension") { - integration.config.widgetLayout = "Dymension"; - integration.config.primaryColor = "29 13% 45%"; - } - - return integration; - } catch (error) { - return null; - } - }, `integration-single-${slug}`)(slug); + cache(fetchSingleNetwork, `integration-single-${slug}`)(slug); type Callback = (...args: any[]) => Promise; function cache(cb: T, key: string) { From fbb0f9814f6a3960c9e838ce50a4535ea51beb44 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 02:31:47 +0100 Subject: [PATCH 02/57] =?UTF-8?q?=F0=9F=90=9B=20fix=20bug=20with=20refacto?= =?UTF-8?q?red=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/fetch-networks.ts | 205 +++++++++++++++++++++++++++++++++ apps/web/lib/network.ts | 205 +-------------------------------- apps/web/this-is-ridiculous.ts | 2 +- 3 files changed, 207 insertions(+), 205 deletions(-) create mode 100644 apps/web/lib/fetch-networks.ts diff --git a/apps/web/lib/fetch-networks.ts b/apps/web/lib/fetch-networks.ts new file mode 100644 index 000000000..70ff96ae6 --- /dev/null +++ b/apps/web/lib/fetch-networks.ts @@ -0,0 +1,205 @@ +import { env } from "process"; +import { z } from "zod"; + +export const singleNetworkSchema = z.object({ + config: z.object({ + logoUrl: z.string().url(), + rpcUrls: z.record( + z.enum(["evm", "cosmos", "svm", "celestia"]), + z.string().url(), + ), + token: z.object({ + name: z.string().max(128), + decimals: z.number(), + }), + platform: z.string().max(64).optional(), + // TODO : These are defaulted for now, but it should be returned by the API + widgetLayout: z + .enum(["EvmWithPrice", "EvmWithoutPrice", "SVM", "Celestia", "Dymension"]) + .optional() + .catch(undefined), + // This is in HSL format, and is used like this : hsl("224 94% 51%") + primaryColor: z.string().optional().default("256 100% 67%"), + cssGradient: z + .string() + .optional() + // this value is directly used as `background-image: linear-gradient(90deg, #0F4EF7 -10.76%, #00D5E2 98.22%);` + .default( + `linear-gradient(94deg, #6833FF 19.54%, #336CFF 75.56%, #33B6FF 93.7%)`, + ), + ecosystems: z.array(z.string()).optional().default([]), + description: z.string().optional(), + type: z.string().optional().default("Execution Layer"), + links: z + .array( + z.object({ + type: z.enum(["website", "github", "x", "discord"]), + href: z.string().url(), + }), + ) + .optional() + .default([]), + badges: z + .array( + z.object({ + relation: z.string().nonempty(), + target: z.string().nonempty(), + logoURL: z.string().url().optional(), + href: z.string().optional(), + }), + ) + .default([]), + }), + paidVersion: z.boolean(), + slug: z.string(), + chainName: z.string(), + brand: z.string(), + accountId: z.string(), + internalId: z.string(), + integrationId: z.string().uuid(), + createdTime: z.coerce.date(), +}); + +export type SingleNetwork = z.infer; + +export async function fetchSingleNetwork(slug: string) { + const describeIntegrationBySlugAPISchema = z.object({ + result: z.object({ + integration: singleNetworkSchema, + }), + }); + + try { + let integration: SingleNetwork | null = null; + + if (!integration) { + let { result } = await fetch( + `${ + env.INTERNAL_INTEGRATION_API_URL + }/integrations/slug/${encodeURIComponent(slug)}`, + ) + .then((r) => r.json()) + .then((data) => describeIntegrationBySlugAPISchema.parse(data)); + + integration = result.integration; + } + + // FIXME : this is hardcoded because widgets are not supported yet on other networks other than these + if (integration.slug === "nautilus-mainnet") { + integration.config.widgetLayout = "EvmWithPrice"; + } + if (integration.brand === "celestia") { + integration.config = { + ...integration.config, + widgetLayout: "Celestia", + logoUrl: "/images/celestia-logo-white.svg", + primaryColor: "256.07 100% 67.06%", + cssGradient: `linear-gradient(89deg, #8457FF -17.52%, #501FD7 89.78%);`, + description: + "Celestia is a modular data availability network that securely scales with the number of users, making it easy for anyone to launch their own blockchain.", + links: [], + }; + } + if (integration.brand === "eclipse") { + integration.config = { + ...integration.config, + widgetLayout: "SVM", + logoUrl: "/images/eclipse-logo-white.svg", + primaryColor: "119.25 33.33% 52.94%", + cssGradient: `linear-gradient(180deg, #65BB64 0%, #569B55 99.99%, #000 100%);`, + description: + "Eclipse is Ethereum's fastest L2, powered by the Solana Virtual Machine.", + links: [], + badges: [ + { + relation: "Settlement", + target: "Sepolia", + logoURL: "/images/ethereum.png", + }, + { + relation: "DA", + target: "Mocha", + logoURL: "/images/celestia-logo-small.png", + href: "/celestia-mocha", + }, + ], + }; + } + if (integration.brand === "dymension") { + integration.config = { + ...integration.config, + widgetLayout: "Dymension", + logoUrl: "/images/dymension-logo-white.svg", + cssGradient: `linear-gradient(89deg, #24201F -17.52%, #24201F 89.78%);`, + primaryColor: "12 7.46% 13.14%", + description: + "Dymension is a home for easily deployable and lightning fast app-chains, called RollApps.", + links: [], + }; + } + + return integration; + } catch (error) { + return null; + } +} + +export async function fetchAllNetworks() { + let allIntegrations: Array = []; + + let nextToken: string | null = null; + + do { + const sp = new URLSearchParams({ + returnAll: "true", + maxResults: "1000", + nextToken: nextToken ?? "", + }); + const response = await fetch( + `${ + env.INTERNAL_INTEGRATION_API_URL + }/integrations-summary?${sp.toString()}`, + ).then(async (r) => { + const text = await r.text(); + const status = r.status; + if (status !== 200) { + console.log({ + res: text, + status: r.status, + statusText: r.statusText, + }); + } + return JSON.parse(text); + }); + + const integrationSummaryAPISchema = z.object({ + result: z + .object({ + integrations: z.array(singleNetworkSchema.nullable().catch(null)), + nextToken: z.string().nullish(), + }) + .nullish(), + }); + const { result } = integrationSummaryAPISchema.parse(response); + nextToken = result?.nextToken ?? null; + + if (result?.integrations) { + for (const integration of result.integrations) { + if (integration !== null) { + allIntegrations.push(integration); + } + } + } + } while (nextToken); + + return allIntegrations.sort((a, b) => { + // prioritize celestia before every other chain + if (a.brand === "celestia") return -1; + if (b.brand === "celestia") return 1; + + // put non paid chains at the end + if (!a.paidVersion) return 1; + if (!b.paidVersion) return -1; + return 0; + }); +} diff --git a/apps/web/lib/network.ts b/apps/web/lib/network.ts index dea8de42f..efb848f6f 100644 --- a/apps/web/lib/network.ts +++ b/apps/web/lib/network.ts @@ -1,69 +1,8 @@ import "server-only"; import { z } from "zod"; -import { env } from "~/env.mjs"; import { cache } from "react"; import { integrations, integrationList } from "~/lib/cache"; - -export const singleNetworkSchema = z.object({ - config: z.object({ - logoUrl: z.string().url(), - rpcUrls: z.record( - z.enum(["evm", "cosmos", "svm", "celestia"]), - z.string().url(), - ), - token: z.object({ - name: z.string().max(128), - decimals: z.number(), - }), - platform: z.string().max(64).optional(), - // TODO : These are defaulted for now, but it should be returned by the API - widgetLayout: z - .enum(["EvmWithPrice", "EvmWithoutPrice", "SVM", "Celestia", "Dymension"]) - .optional() - .catch(undefined), - // This is in HSL format, and is used like this : hsl("224 94% 51%") - primaryColor: z.string().optional().default("256 100% 67%"), - cssGradient: z - .string() - .optional() - // this value is directly used as `background-image: linear-gradient(90deg, #0F4EF7 -10.76%, #00D5E2 98.22%);` - .default( - `linear-gradient(94deg, #6833FF 19.54%, #336CFF 75.56%, #33B6FF 93.7%)`, - ), - ecosystems: z.array(z.string()).optional().default([]), - description: z.string().optional(), - type: z.string().optional().default("Execution Layer"), - links: z - .array( - z.object({ - type: z.enum(["website", "github", "x", "discord"]), - href: z.string().url(), - }), - ) - .optional() - .default([]), - badges: z - .array( - z.object({ - relation: z.string().nonempty(), - target: z.string().nonempty(), - logoURL: z.string().url().optional(), - href: z.string().optional(), - }), - ) - .default([]), - }), - paidVersion: z.boolean(), - slug: z.string(), - chainName: z.string(), - brand: z.string(), - accountId: z.string(), - internalId: z.string(), - integrationId: z.string().uuid(), - createdTime: z.coerce.date(), -}); - -export type SingleNetwork = z.infer; +import { singleNetworkSchema, fetchSingleNetwork } from "./fetch-networks"; const allNetworkSchema = z.array(singleNetworkSchema); @@ -83,148 +22,6 @@ export const getSingleNetwork = cache(async function getSingleNetwork( } }); -export async function fetchSingleNetwork(slug: string) { - const describeIntegrationBySlugAPISchema = z.object({ - result: z.object({ - integration: singleNetworkSchema, - }), - }); - - try { - let integration: SingleNetwork | null = null; - - if (!integration) { - let { result } = await fetch( - `${ - env.INTERNAL_INTEGRATION_API_URL - }/integrations/slug/${encodeURIComponent(slug)}`, - ) - .then((r) => r.json()) - .then((data) => describeIntegrationBySlugAPISchema.parse(data)); - - integration = result.integration; - } - - // FIXME : this is hardcoded because widgets are not supported yet on other networks other than these - if (integration.slug === "nautilus-mainnet") { - integration.config.widgetLayout = "EvmWithPrice"; - } - if (integration.brand === "celestia") { - integration.config = { - ...integration.config, - widgetLayout: "Celestia", - logoUrl: "/images/celestia-logo-white.svg", - primaryColor: "256.07 100% 67.06%", - cssGradient: `linear-gradient(89deg, #8457FF -17.52%, #501FD7 89.78%);`, - description: - "Celestia is a modular data availability network that securely scales with the number of users, making it easy for anyone to launch their own blockchain.", - links: [], - }; - } - if (integration.brand === "eclipse") { - integration.config = { - ...integration.config, - widgetLayout: "SVM", - logoUrl: "/images/eclipse-logo-white.svg", - primaryColor: "119.25 33.33% 52.94%", - cssGradient: `linear-gradient(180deg, #65BB64 0%, #569B55 99.99%, #000 100%);`, - description: - "Eclipse is Ethereum's fastest L2, powered by the Solana Virtual Machine.", - links: [], - badges: [ - { - relation: "Settlement", - target: "Sepolia", - logoURL: "/images/ethereum.png", - }, - { - relation: "DA", - target: "Mocha", - logoURL: "/images/celestia-logo-small.png", - href: "/celestia-mocha", - }, - ], - }; - } - if (integration.brand === "dymension") { - integration.config = { - ...integration.config, - widgetLayout: "Dymension", - logoUrl: "/images/dymension-logo-white.svg", - cssGradient: `linear-gradient(89deg, #24201F -17.52%, #24201F 89.78%);`, - primaryColor: "12 7.46% 13.14%", - description: - "Dymension is a home for easily deployable and lightning fast app-chains, called RollApps.", - links: [], - }; - } - - return integration; - } catch (error) { - return null; - } -} - -export async function fetchAllNetworks() { - let allIntegrations: Array = []; - - let nextToken: string | null = null; - - do { - const sp = new URLSearchParams({ - returnAll: "true", - maxResults: "1000", - nextToken: nextToken ?? "", - }); - const response = await fetch( - `${ - env.INTERNAL_INTEGRATION_API_URL - }/integrations-summary?${sp.toString()}`, - ).then(async (r) => { - const text = await r.text(); - const status = r.status; - if (status !== 200) { - console.log({ - res: text, - status: r.status, - statusText: r.statusText, - }); - } - return JSON.parse(text); - }); - - const integrationSummaryAPISchema = z.object({ - result: z - .object({ - integrations: z.array(singleNetworkSchema.nullable().catch(null)), - nextToken: z.string().nullish(), - }) - .nullish(), - }); - const { result } = integrationSummaryAPISchema.parse(response); - nextToken = result?.nextToken ?? null; - - if (result?.integrations) { - for (const integration of result.integrations) { - if (integration !== null) { - allIntegrations.push(integration); - } - } - } - } while (nextToken); - - return allIntegrations.sort((a, b) => { - // prioritize celestia before every other chain - if (a.brand === "celestia") return -1; - if (b.brand === "celestia") return 1; - - // put non paid chains at the end - if (!a.paidVersion) return 1; - if (!b.paidVersion) return -1; - return 0; - }); -} - export const getAllPaidNetworks = cache(async function getAllPaidNetworks() { const allNetworks = getAllNetworks(); return allNetworks.filter((network) => network.paidVersion).slice(0, 30); diff --git a/apps/web/this-is-ridiculous.ts b/apps/web/this-is-ridiculous.ts index 857dc056e..58074a671 100644 --- a/apps/web/this-is-ridiculous.ts +++ b/apps/web/this-is-ridiculous.ts @@ -6,7 +6,7 @@ import fs from "node:fs/promises"; import { FileSystemCacheDEV } from "~/lib/fs-cache-dev"; import { capitalize } from "./lib/shared-utils"; -import { fetchSingleNetwork, fetchAllNetworks } from "./lib/network"; +import { fetchSingleNetwork, fetchAllNetworks } from "./lib/fetch-networks"; const getAllNetworks = cache(fetchAllNetworks, "integration-summary"); From 2b290c025457dd7fe17f766d1cc5b9445c7fd8c0 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 02:36:00 +0100 Subject: [PATCH 03/57] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20fix=20type=20impo?= =?UTF-8?q?rts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/grouped-network-chains.ts | 3 ++- apps/web/ui/right-panel/index.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/web/lib/grouped-network-chains.ts b/apps/web/lib/grouped-network-chains.ts index 662ed03be..2cae6f1be 100644 --- a/apps/web/lib/grouped-network-chains.ts +++ b/apps/web/lib/grouped-network-chains.ts @@ -1,7 +1,8 @@ import "server-only"; -import { type SingleNetwork, getAllNetworks } from "./network"; +import { getAllNetworks } from "./network"; import { arrayGroupByTo2DArray } from "./shared-utils"; import { cache } from "react"; +import type { SingleNetwork } from "./fetch-networks"; /** * Transform the list of integrations to a `searchOptions` object diff --git a/apps/web/ui/right-panel/index.tsx b/apps/web/ui/right-panel/index.tsx index 283d420a3..a3558dcf6 100644 --- a/apps/web/ui/right-panel/index.tsx +++ b/apps/web/ui/right-panel/index.tsx @@ -16,7 +16,7 @@ import { cn } from "~/ui/shadcn/utils"; // types import type { ShortcutKeyProps } from "~/ui/shortcut-key"; -import type { SingleNetwork } from "~/lib/network"; +import type { SingleNetwork } from "~/lib/fetch-networks"; import type { Page } from "@modularcloud/headless"; interface HotkeyEntryProps { From 14d8b1ab9c2e35732d7e9276b07e98109787f21b Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 02:43:39 +0100 Subject: [PATCH 04/57] =?UTF-8?q?=F0=9F=A4=A1=20complete=20links=20informa?= =?UTF-8?q?tion=20for=20each=20brand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/fetch-networks.ts | 45 +++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/apps/web/lib/fetch-networks.ts b/apps/web/lib/fetch-networks.ts index 70ff96ae6..f7e3938f6 100644 --- a/apps/web/lib/fetch-networks.ts +++ b/apps/web/lib/fetch-networks.ts @@ -97,7 +97,24 @@ export async function fetchSingleNetwork(slug: string) { cssGradient: `linear-gradient(89deg, #8457FF -17.52%, #501FD7 89.78%);`, description: "Celestia is a modular data availability network that securely scales with the number of users, making it easy for anyone to launch their own blockchain.", - links: [], + links: [ + { + type: "website", + href: "https://celestia.org/", + }, + { + type: "github", + href: "https://github.com/celestiaorg", + }, + { + type: "discord", + href: "https://discord.com/invite/YsnTPcSfWQ", + }, + { + type: "x", + href: "https://twitter.com/CelestiaOrg/", + }, + ], }; } if (integration.brand === "eclipse") { @@ -109,7 +126,16 @@ export async function fetchSingleNetwork(slug: string) { cssGradient: `linear-gradient(180deg, #65BB64 0%, #569B55 99.99%, #000 100%);`, description: "Eclipse is Ethereum's fastest L2, powered by the Solana Virtual Machine.", - links: [], + links: [ + { + type: "website", + href: "https://www.eclipse.builders/", + }, + { + type: "x", + href: "https://twitter.com/EclipseFND", + }, + ], badges: [ { relation: "Settlement", @@ -134,7 +160,20 @@ export async function fetchSingleNetwork(slug: string) { primaryColor: "12 7.46% 13.14%", description: "Dymension is a home for easily deployable and lightning fast app-chains, called RollApps.", - links: [], + links: [ + { + type: "website", + href: "https://portal.dymension.xyz", + }, + { + type: "github", + href: "https://github.com/dymensionxyz", + }, + { + type: "x", + href: "https://twitter.com/dymension", + }, + ], }; } From fdd9dba502d117fb2be641f14d879483e80ad200 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 02:50:31 +0100 Subject: [PATCH 05/57] =?UTF-8?q?=F0=9F=8E=A8=20format=20`settings.json`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 49a95ade4..f7f353781 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,5 @@ "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.defaultFormatter": "esbenp.prettier-vscode" } From 33d701fb473b7075d2ddf247fa4598d2f01b99fc Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 04:03:16 +0100 Subject: [PATCH 06/57] =?UTF-8?q?=E2=9C=A8=20OG=20favicon=20images?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/app/(home)/[network]/page.tsx | 6 ++ apps/web/app/(home)/layout.tsx | 7 ++ apps/web/app/api/og/components/favicon.tsx | 27 ++++++ apps/web/app/api/og/components/mc-logo.tsx | 80 ++++++++++++++++ .../app/api/og/components/opengraph-home.tsx | 92 +------------------ apps/web/app/api/og/route.tsx | 78 ++++++++++++---- apps/web/lib/fetch-networks.ts | 12 ++- 7 files changed, 189 insertions(+), 113 deletions(-) create mode 100644 apps/web/app/api/og/components/favicon.tsx create mode 100644 apps/web/app/api/og/components/mc-logo.tsx diff --git a/apps/web/app/(home)/[network]/page.tsx b/apps/web/app/(home)/[network]/page.tsx index 1edbf40af..6b0af4544 100644 --- a/apps/web/app/(home)/[network]/page.tsx +++ b/apps/web/app/(home)/[network]/page.tsx @@ -34,6 +34,12 @@ export async function generateMetadata(props: Props): Promise { }, ], }, + icons: [ + { + rel: "icon", + url: `/api/og?model=favicon&networkSlug=${network.slug}`, + }, + ], }; } diff --git a/apps/web/app/(home)/layout.tsx b/apps/web/app/(home)/layout.tsx index 85fb3b6da..1a48fb310 100644 --- a/apps/web/app/(home)/layout.tsx +++ b/apps/web/app/(home)/layout.tsx @@ -9,6 +9,13 @@ export default async function HomeLayout({ children: React.ReactNode; }) { return ( + //
+ //
{children}
+ //
+ + + ); +} diff --git a/apps/web/app/api/og/components/mc-logo.tsx b/apps/web/app/api/og/components/mc-logo.tsx new file mode 100644 index 000000000..29fdf30f8 --- /dev/null +++ b/apps/web/app/api/og/components/mc-logo.tsx @@ -0,0 +1,80 @@ +export function MCLogo(props: React.SVGProps) { + 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..3039cb129 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 "./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 ( res.arrayBuffer()); + const fonts: Array = []; + try { + const geistMedium = await fetch( + new URL("../../../public/fonts/Geist/Geist-Medium.otf", import.meta.url), + ).then((res) => res.arrayBuffer()); + fonts.push({ + name: "Geist", + data: geistMedium, + style: "normal", + weight: 500, + }); + } catch (error) { + const baseUrl = env.NEXT_PUBLIC_VERCEL_URL ?? "http://127.0.0.1:3000"; + const geistMedium = await fetch( + new URL(`${baseUrl}/fonts/Geist/Geist-Medium.otf`), + ).then((res) => res.arrayBuffer()); + fonts.push({ + name: "Geist", + data: geistMedium, + style: "normal", + weight: 500, + }); + } - return new ImageResponse( - <>{await OpenGraphHome({ networkSlug: params.networkSlug })}, - { - ...OG_SIZE, - fonts: [ + switch (params.model) { + case "network-home": + return new ImageResponse(, { + ...OG_SIZE, + fonts, + }); + case "favicon": + return new ImageResponse( + , { - name: "Geist", - data: geistMedium, - style: "normal", - weight: 500, + width: 32, + height: 32, + fonts, }, - ], - }, - ); + ); + default: + notFound(); + } } diff --git a/apps/web/lib/fetch-networks.ts b/apps/web/lib/fetch-networks.ts index f7e3938f6..f91fe7c9f 100644 --- a/apps/web/lib/fetch-networks.ts +++ b/apps/web/lib/fetch-networks.ts @@ -84,6 +84,8 @@ export async function fetchSingleNetwork(slug: string) { integration = result.integration; } + const baseUrl = env.NEXT_PUBLIC_VERCEL_URL ?? "http://127.0.0.1:3000"; + // FIXME : this is hardcoded because widgets are not supported yet on other networks other than these if (integration.slug === "nautilus-mainnet") { integration.config.widgetLayout = "EvmWithPrice"; @@ -92,7 +94,7 @@ export async function fetchSingleNetwork(slug: string) { integration.config = { ...integration.config, widgetLayout: "Celestia", - logoUrl: "/images/celestia-logo-white.svg", + logoUrl: `${baseUrl}/images/celestia-logo-white.svg`, primaryColor: "256.07 100% 67.06%", cssGradient: `linear-gradient(89deg, #8457FF -17.52%, #501FD7 89.78%);`, description: @@ -121,7 +123,7 @@ export async function fetchSingleNetwork(slug: string) { integration.config = { ...integration.config, widgetLayout: "SVM", - logoUrl: "/images/eclipse-logo-white.svg", + logoUrl: `${baseUrl}/images/eclipse-logo-white.svg`, primaryColor: "119.25 33.33% 52.94%", cssGradient: `linear-gradient(180deg, #65BB64 0%, #569B55 99.99%, #000 100%);`, description: @@ -140,12 +142,12 @@ export async function fetchSingleNetwork(slug: string) { { relation: "Settlement", target: "Sepolia", - logoURL: "/images/ethereum.png", + logoURL: `${baseUrl}/images/ethereum.png`, }, { relation: "DA", target: "Mocha", - logoURL: "/images/celestia-logo-small.png", + logoURL: `${baseUrl}/images/celestia-logo-small.png`, href: "/celestia-mocha", }, ], @@ -155,7 +157,7 @@ export async function fetchSingleNetwork(slug: string) { integration.config = { ...integration.config, widgetLayout: "Dymension", - logoUrl: "/images/dymension-logo-white.svg", + logoUrl: `${baseUrl}/images/dymension-logo-white.svg`, cssGradient: `linear-gradient(89deg, #24201F -17.52%, #24201F 89.78%);`, primaryColor: "12 7.46% 13.14%", description: From f3db0a736c4076d69102a7753993482ff3bc16fb Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 23:18:05 +0100 Subject: [PATCH 07/57] =?UTF-8?q?=F0=9F=94=8A=20some=20log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/app/api/og/route.tsx | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/apps/web/app/api/og/route.tsx b/apps/web/app/api/og/route.tsx index 1fa251fda..e1ba8b841 100644 --- a/apps/web/app/api/og/route.tsx +++ b/apps/web/app/api/og/route.tsx @@ -8,15 +8,10 @@ import { getSingleNetwork } from "~/lib/network"; import { Favicon } from "./components/favicon"; import { notFound } from "next/navigation"; -const ogSearchParamsSchema = z.union([ - z.object({ - model: z.enum(["network-home", "favicon"]), - networkSlug: z.string(), - }), - z.object({ - model: z.enum(["other"]), - }), -]); +const ogSearchParamsSchema = z.object({ + model: z.enum(["network-home", "favicon"]), + networkSlug: z.string(), +}); export const runtime = "edge"; @@ -31,18 +26,16 @@ export async function GET(req: NextRequest) { const searchParams = Object.fromEntries(req.nextUrl.searchParams.entries()); const paramsResult = ogSearchParamsSchema.safeParse(searchParams); if (!paramsResult.success) { - return new Response(null, { - status: 404, - }); + notFound(); } const params = paramsResult.data; - if (params.model === "other") { - notFound(); - } - const network = await getSingleNetwork(params.networkSlug); + console.log({ + network, + params, + }); if (!network) { notFound(); } From c3cf7bb66a53a0ba12a61486985db55c1c285427 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 23:43:23 +0100 Subject: [PATCH 08/57] =?UTF-8?q?=F0=9F=94=8A=20more=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/fetch-networks.ts | 4 ++++ apps/web/lib/network.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/web/lib/fetch-networks.ts b/apps/web/lib/fetch-networks.ts index f91fe7c9f..462914bea 100644 --- a/apps/web/lib/fetch-networks.ts +++ b/apps/web/lib/fetch-networks.ts @@ -77,6 +77,9 @@ export async function fetchSingleNetwork(slug: string) { `${ env.INTERNAL_INTEGRATION_API_URL }/integrations/slug/${encodeURIComponent(slug)}`, + { + cache: "force-cache", + }, ) .then((r) => r.json()) .then((data) => describeIntegrationBySlugAPISchema.parse(data)); @@ -200,6 +203,7 @@ export async function fetchAllNetworks() { `${ env.INTERNAL_INTEGRATION_API_URL }/integrations-summary?${sp.toString()}`, + { cache: "force-cache" }, ).then(async (r) => { const text = await r.text(); const status = r.status; diff --git a/apps/web/lib/network.ts b/apps/web/lib/network.ts index efb848f6f..ef473ee23 100644 --- a/apps/web/lib/network.ts +++ b/apps/web/lib/network.ts @@ -16,6 +16,10 @@ export const getSingleNetwork = cache(async function getSingleNetwork( try { // @ts-expect-error const found = integrations[slug].value; + console.log({ + found, + integrations, + }); return singleNetworkSchema.parse(found); } catch (error) { return await fetchSingleNetwork(slug); From b011227f514f5d2f2753c35777265053868cdde9 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 27 Feb 2024 23:57:02 +0100 Subject: [PATCH 09/57] =?UTF-8?q?=F0=9F=94=8A=20log=20error=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/network.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/web/lib/network.ts b/apps/web/lib/network.ts index ef473ee23..0bac92bd4 100644 --- a/apps/web/lib/network.ts +++ b/apps/web/lib/network.ts @@ -16,12 +16,9 @@ export const getSingleNetwork = cache(async function getSingleNetwork( try { // @ts-expect-error const found = integrations[slug].value; - console.log({ - found, - integrations, - }); return singleNetworkSchema.parse(found); } catch (error) { + console.error(error); return await fetchSingleNetwork(slug); } }); From 06ce6d3078990a8be22ad2f71315ed6265aaa058 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 00:01:40 +0100 Subject: [PATCH 10/57] =?UTF-8?q?=F0=9F=94=8A=20more=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/network.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/lib/network.ts b/apps/web/lib/network.ts index 0bac92bd4..855533080 100644 --- a/apps/web/lib/network.ts +++ b/apps/web/lib/network.ts @@ -16,6 +16,7 @@ export const getSingleNetwork = cache(async function getSingleNetwork( try { // @ts-expect-error const found = integrations[slug].value; + console.log({ found }); return singleNetworkSchema.parse(found); } catch (error) { console.error(error); From 18f0e34059862aae1438b968bb52a864d431f319 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 00:09:19 +0100 Subject: [PATCH 11/57] =?UTF-8?q?=F0=9F=90=9B=20use=20correct=20baseURL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/fetch-networks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/lib/fetch-networks.ts b/apps/web/lib/fetch-networks.ts index 462914bea..d939986c2 100644 --- a/apps/web/lib/fetch-networks.ts +++ b/apps/web/lib/fetch-networks.ts @@ -1,4 +1,4 @@ -import { env } from "process"; +import { env } from "~/env.mjs"; import { z } from "zod"; export const singleNetworkSchema = z.object({ From 991e6e6891365ad98da0e0a01960bcf01c7c3a01 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 00:15:37 +0100 Subject: [PATCH 12/57] =?UTF-8?q?=E2=9A=97=EF=B8=8F=20throw=20error=20on?= =?UTF-8?q?=20bad=20request?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/fetch-networks.ts | 2 ++ apps/web/this-is-ridiculous.ts | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/lib/fetch-networks.ts b/apps/web/lib/fetch-networks.ts index d939986c2..fc43c2e6e 100644 --- a/apps/web/lib/fetch-networks.ts +++ b/apps/web/lib/fetch-networks.ts @@ -212,7 +212,9 @@ export async function fetchAllNetworks() { res: text, status: r.status, statusText: r.statusText, + url: r.url, }); + throw new Error(text); } return JSON.parse(text); }); diff --git a/apps/web/this-is-ridiculous.ts b/apps/web/this-is-ridiculous.ts index 58074a671..bb5f9e315 100644 --- a/apps/web/this-is-ridiculous.ts +++ b/apps/web/this-is-ridiculous.ts @@ -32,8 +32,6 @@ async function getAllPaidNetworks() { return allNetworks.filter((network) => network.paidVersion).slice(0, 30); } -await getAllNetworks(); - const paidNetworks = await getAllPaidNetworks(); let template = `export { default as integrationList } from "./integration-summary.json";`; From fc36d539d42da7c6c2171bd4c2921f18648ddda2 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 00:24:18 +0100 Subject: [PATCH 13/57] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Use=20the=20producti?= =?UTF-8?q?on=20URL=20on=20vercel=20production=20env?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/lib/fetch-networks.ts | 5 ++++- apps/web/lib/network.ts | 2 -- turbo.json | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/web/lib/fetch-networks.ts b/apps/web/lib/fetch-networks.ts index fc43c2e6e..b0d4de823 100644 --- a/apps/web/lib/fetch-networks.ts +++ b/apps/web/lib/fetch-networks.ts @@ -87,7 +87,10 @@ export async function fetchSingleNetwork(slug: string) { integration = result.integration; } - const baseUrl = env.NEXT_PUBLIC_VERCEL_URL ?? "http://127.0.0.1:3000"; + let baseUrl = env.NEXT_PUBLIC_VERCEL_URL ?? "http://127.0.0.1:3000"; + if (process.env.VERCEL_ENV === "production") { + baseUrl = env.NEXT_PUBLIC_PRODUCTION_URL; + } // FIXME : this is hardcoded because widgets are not supported yet on other networks other than these if (integration.slug === "nautilus-mainnet") { diff --git a/apps/web/lib/network.ts b/apps/web/lib/network.ts index 855533080..efb848f6f 100644 --- a/apps/web/lib/network.ts +++ b/apps/web/lib/network.ts @@ -16,10 +16,8 @@ export const getSingleNetwork = cache(async function getSingleNetwork( try { // @ts-expect-error const found = integrations[slug].value; - console.log({ found }); return singleNetworkSchema.parse(found); } catch (error) { - console.error(error); return await fetchSingleNetwork(slug); } }); diff --git a/turbo.json b/turbo.json index 779050f9f..c4498a398 100644 --- a/turbo.json +++ b/turbo.json @@ -54,7 +54,8 @@ "CELESTIA_MAINNET_BACKUP_NODE", "NEXT_PUBLIC_ADOBE_EMBED_API_KEY", "BLOB_READ_WRITE_TOKEN", - "NEXT_PUBLIC_PRODUCTION_URL" + "NEXT_PUBLIC_PRODUCTION_URL", + "VERCEL_ENV" ] }, "verify#build": { From 1d5469e02211fd6d49a542a125e6009c7970ad1b Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 00:32:24 +0100 Subject: [PATCH 14/57] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20use=20branded=20favi?= =?UTF-8?q?cons=20in=20transaction=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/(entity)/[network]/[...path]/page.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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({ From 5dcdc407c1b9fe1e948d0167695e6bb176f9a0f0 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 00:54:07 +0100 Subject: [PATCH 15/57] =?UTF-8?q?=F0=9F=9A=9A=20move=20header=20to=20entit?= =?UTF-8?q?y-header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/app/(entity)/[network]/layout.tsx | 4 ++-- .../entity-header-search-button.tsx} | 2 +- .../entity-header-summary.tsx} | 8 ++------ apps/web/ui/{header => entity-header}/index.tsx | 10 +++++----- 4 files changed, 10 insertions(+), 14 deletions(-) rename apps/web/ui/{header/header-search-button.tsx => entity-header/entity-header-search-button.tsx} (98%) rename apps/web/ui/{header/header-entity-highlight.tsx => entity-header/entity-header-summary.tsx} (93%) rename apps/web/ui/{header => entity-header}/index.tsx (77%) 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({ > -
+
Modular Cloud - + {/* Bigger screens */}
- + ); } From a7d56e493086babc95ea21b294b269d33dcf2112 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 02:07:56 +0100 Subject: [PATCH 16/57] =?UTF-8?q?=F0=9F=9A=A7=20New=20Header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 5 +- apps/web/app/(entity)/[network]/error.tsx | 4 +- apps/web/app/(home)/layout.tsx | 40 ++-- apps/web/app/api/og/components/favicon.tsx | 8 +- .../app/api/og/components/opengraph-home.tsx | 2 +- apps/web/app/layout.tsx | 6 +- apps/web/lib/fetch-networks.ts | 189 ++++++++++-------- apps/web/lib/grouped-network-chains.ts | 9 +- apps/web/ui/client-providers/index.tsx | 6 +- .../entity-header-search-button.tsx | 8 +- .../entity-header/entity-header-summary.tsx | 15 +- apps/web/ui/entity-header/index.tsx | 7 +- .../web/ui/grouped-networks-context/index.tsx | 29 +++ apps/web/ui/header/branded-logo.tsx | 31 +++ apps/web/ui/header/header-search-button.tsx | 65 ++++++ apps/web/ui/header/index.tsx | 18 ++ .../mc-logo.tsx => ui/mc-logo/index.tsx} | 0 apps/web/ui/search-options-context/index.tsx | 31 --- apps/web/ui/search/integration-grid-view.tsx | 4 +- apps/web/ui/search/search-form.tsx | 4 +- 20 files changed, 304 insertions(+), 177 deletions(-) create mode 100644 apps/web/ui/grouped-networks-context/index.tsx create mode 100644 apps/web/ui/header/branded-logo.tsx create mode 100644 apps/web/ui/header/header-search-button.tsx create mode 100644 apps/web/ui/header/index.tsx rename apps/web/{app/api/og/components/mc-logo.tsx => ui/mc-logo/index.tsx} (100%) delete mode 100644 apps/web/ui/search-options-context/index.tsx diff --git a/.vscode/settings.json b/.vscode/settings.json index f7f353781..34b126643 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,8 @@ "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } } 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/(home)/layout.tsx b/apps/web/app/(home)/layout.tsx index 1a48fb310..0d05a66e5 100644 --- a/apps/web/app/(home)/layout.tsx +++ b/apps/web/app/(home)/layout.tsx @@ -1,5 +1,8 @@ +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, @@ -9,27 +12,32 @@ export default async function HomeLayout({ children: React.ReactNode; }) { return ( - //
- //
{children}
- //
-
-
- {logo} - -
-
{children}
-
+ + + +
-
+ {/*
{children}
*/}
+ //
+ //
+ //
+ // {logo} + // + //
+ //
{children}
+ //
+ + //
+ //
); } diff --git a/apps/web/app/api/og/components/favicon.tsx b/apps/web/app/api/og/components/favicon.tsx index 1333649ca..d36d7d0f0 100644 --- a/apps/web/app/api/og/components/favicon.tsx +++ b/apps/web/app/api/og/components/favicon.tsx @@ -1,17 +1,13 @@ -import { MCLogo } from "./mc-logo"; +import { MCLogo } from "~/ui/mc-logo"; export type FaviconProps = { networkBrandGradient: string; }; export function Favicon({ networkBrandGradient }: FaviconProps) { - console.log({ - bgImage: networkBrandGradient, - }); return (
@@ -70,8 +70,8 @@ export default async function RootLayout({ suppressHydrationWarning > - - + + {children} {process.env.NODE_ENV !== "production" && } diff --git a/apps/web/lib/fetch-networks.ts b/apps/web/lib/fetch-networks.ts index b0d4de823..0b9bd3025 100644 --- a/apps/web/lib/fetch-networks.ts +++ b/apps/web/lib/fetch-networks.ts @@ -96,94 +96,10 @@ export async function fetchSingleNetwork(slug: string) { if (integration.slug === "nautilus-mainnet") { integration.config.widgetLayout = "EvmWithPrice"; } - if (integration.brand === "celestia") { - integration.config = { - ...integration.config, - widgetLayout: "Celestia", - logoUrl: `${baseUrl}/images/celestia-logo-white.svg`, - primaryColor: "256.07 100% 67.06%", - cssGradient: `linear-gradient(89deg, #8457FF -17.52%, #501FD7 89.78%);`, - description: - "Celestia is a modular data availability network that securely scales with the number of users, making it easy for anyone to launch their own blockchain.", - links: [ - { - type: "website", - href: "https://celestia.org/", - }, - { - type: "github", - href: "https://github.com/celestiaorg", - }, - { - type: "discord", - href: "https://discord.com/invite/YsnTPcSfWQ", - }, - { - type: "x", - href: "https://twitter.com/CelestiaOrg/", - }, - ], - }; - } - if (integration.brand === "eclipse") { - integration.config = { - ...integration.config, - widgetLayout: "SVM", - logoUrl: `${baseUrl}/images/eclipse-logo-white.svg`, - primaryColor: "119.25 33.33% 52.94%", - cssGradient: `linear-gradient(180deg, #65BB64 0%, #569B55 99.99%, #000 100%);`, - description: - "Eclipse is Ethereum's fastest L2, powered by the Solana Virtual Machine.", - links: [ - { - type: "website", - href: "https://www.eclipse.builders/", - }, - { - type: "x", - href: "https://twitter.com/EclipseFND", - }, - ], - badges: [ - { - relation: "Settlement", - target: "Sepolia", - logoURL: `${baseUrl}/images/ethereum.png`, - }, - { - relation: "DA", - target: "Mocha", - logoURL: `${baseUrl}/images/celestia-logo-small.png`, - href: "/celestia-mocha", - }, - ], - }; - } - if (integration.brand === "dymension") { - integration.config = { - ...integration.config, - widgetLayout: "Dymension", - logoUrl: `${baseUrl}/images/dymension-logo-white.svg`, - cssGradient: `linear-gradient(89deg, #24201F -17.52%, #24201F 89.78%);`, - primaryColor: "12 7.46% 13.14%", - description: - "Dymension is a home for easily deployable and lightning fast app-chains, called RollApps.", - links: [ - { - type: "website", - href: "https://portal.dymension.xyz", - }, - { - type: "github", - href: "https://github.com/dymensionxyz", - }, - { - type: "x", - href: "https://twitter.com/dymension", - }, - ], - }; - } + integration.config = { + ...integration.config, + ...getDefaultIntegrationConfigValues(integration.brand), + }; return integration; } catch (error) { @@ -191,6 +107,99 @@ export async function fetchSingleNetwork(slug: string) { } } +function getDefaultIntegrationConfigValues( + brand: string, +): Partial { + let baseUrl = env.NEXT_PUBLIC_VERCEL_URL ?? "http://127.0.0.1:3000"; + if (process.env.VERCEL_ENV === "production") { + baseUrl = env.NEXT_PUBLIC_PRODUCTION_URL; + } + if (brand === "celestia") { + return { + widgetLayout: "Celestia", + primaryColor: "256.07 100% 67.06%", + cssGradient: `linear-gradient(89deg, #8457FF -17.52%, #501FD7 89.78%)`, + description: + "Celestia is a modular data availability network that securely scales with the number of users, making it easy for anyone to launch their own blockchain.", + links: [ + { + type: "website", + href: "https://celestia.org/", + }, + { + type: "github", + href: "https://github.com/celestiaorg", + }, + { + type: "discord", + href: "https://discord.com/invite/YsnTPcSfWQ", + }, + { + type: "x", + href: "https://twitter.com/CelestiaOrg/", + }, + ], + }; + } + if (brand === "eclipse") { + return { + widgetLayout: "SVM", + primaryColor: "119.25 33.33% 52.94%", + cssGradient: `linear-gradient(180deg, #65BB64 0%, #569B55 99.99%, #000 100%)`, + description: + "Eclipse is Ethereum's fastest L2, powered by the Solana Virtual Machine.", + links: [ + { + type: "website", + href: "https://www.eclipse.builders/", + }, + { + type: "x", + href: "https://twitter.com/EclipseFND", + }, + ], + badges: [ + { + relation: "Settlement", + target: "Sepolia", + logoURL: `${baseUrl}/images/ethereum.png`, + }, + { + relation: "DA", + target: "Mocha", + logoURL: `${baseUrl}/images/celestia-logo-small.png`, + href: "/celestia-mocha", + }, + ], + }; + } + if (brand === "dymension") { + return { + widgetLayout: "Dymension", + cssGradient: `linear-gradient(89deg, #24201F -17.52%, #24201F 89.78%)`, + primaryColor: "12 7.46% 13.14%", + description: + "Dymension is a home for easily deployable and lightning fast app-chains, called RollApps.", + links: [ + { + type: "website", + href: "https://portal.dymension.xyz", + }, + { + type: "github", + href: "https://github.com/dymensionxyz", + }, + { + type: "x", + href: "https://twitter.com/dymension", + }, + ], + }; + } + + return {}; +} + export async function fetchAllNetworks() { let allIntegrations: Array = []; @@ -236,6 +245,10 @@ export async function fetchAllNetworks() { if (result?.integrations) { for (const integration of result.integrations) { if (integration !== null) { + integration.config = { + ...integration.config, + ...getDefaultIntegrationConfigValues(integration.brand), + }; allIntegrations.push(integration); } } diff --git a/apps/web/lib/grouped-network-chains.ts b/apps/web/lib/grouped-network-chains.ts index 2cae6f1be..37270f18f 100644 --- a/apps/web/lib/grouped-network-chains.ts +++ b/apps/web/lib/grouped-network-chains.ts @@ -11,7 +11,7 @@ import type { SingleNetwork } from "./fetch-networks"; */ export const getGroupedNetworkChains = cache( async function getGroupedNetworkChains() { - const integrations = await getAllNetworks(); + const integrations = getAllNetworks(); const options: NetworkChain[] = integrations.map((currentNetwork) => ({ brandColor: currentNetwork.config.primaryColor, @@ -20,10 +20,14 @@ export const getGroupedNetworkChains = cache( displayName: currentNetwork.chainName, slug: currentNetwork.slug, brandName: currentNetwork.brand, - logoURL: currentNetwork.config.logoUrl, + logoURL: currentNetwork.config.logoUrl.replaceAll( + "http://127.0.0.1:3000", + "", + ), platform: currentNetwork.config.platform, accountId: currentNetwork.accountId, ecosystems: currentNetwork.config.ecosystems, + brandCSSGradient: currentNetwork.config.cssGradient, })); return arrayGroupByTo2DArray(options, "accountId"); @@ -45,4 +49,5 @@ export type NetworkChain = { logoURL: string; slug: string; ecosystems: string[]; + brandCSSGradient: string; }; diff --git a/apps/web/ui/client-providers/index.tsx b/apps/web/ui/client-providers/index.tsx index 6070b6059..ff46fb051 100644 --- a/apps/web/ui/client-providers/index.tsx +++ b/apps/web/ui/client-providers/index.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import type { GroupedNetworkChains } from "~/lib/grouped-network-chains"; -import { SearchOptionProvider } from "~/ui/search-options-context"; +import { GroupedNetworksProvider } from "~/ui/grouped-networks-context"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; @@ -25,9 +25,9 @@ export function ClientProviders({ searchOptions, children }: Props) { return ( - + {children} - + ); diff --git a/apps/web/ui/entity-header/entity-header-search-button.tsx b/apps/web/ui/entity-header/entity-header-search-button.tsx index 7ce994b88..26aba9428 100644 --- a/apps/web/ui/entity-header/entity-header-search-button.tsx +++ b/apps/web/ui/entity-header/entity-header-search-button.tsx @@ -13,15 +13,13 @@ 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; -} +import { useGroupedNetworksContext } from "~/ui/grouped-networks-context"; -export function EntityHeaderSearchButton({ optionGroups }: Props) { +export function EntityHeaderSearchButton() { const routeParams = useParams() as HeadlessRoute; const pathname = usePathname(); + const optionGroups = useGroupedNetworksContext(); const params: HeadlessRoute = { ...routeParams, path: pathname diff --git a/apps/web/ui/entity-header/entity-header-summary.tsx b/apps/web/ui/entity-header/entity-header-summary.tsx index 77d426175..8d187f09e 100644 --- a/apps/web/ui/entity-header/entity-header-summary.tsx +++ b/apps/web/ui/entity-header/entity-header-summary.tsx @@ -3,20 +3,15 @@ import Image from "next/image"; import { useParams } from "next/navigation"; import React from "react"; -import type { GroupedNetworkChains } from "~/lib/grouped-network-chains"; import type { HeadlessRoute } from "~/lib/headless-utils"; import { parseHeadlessRouteVercelFix, capitalize } from "~/lib/shared-utils"; -import { cn } from "../shadcn/utils"; -import { CopyableValue } from "../copyable-value"; +import { cn } from "~/ui/shadcn/utils"; +import { CopyableValue } from "~/ui/copyable-value"; +import { useGroupedNetworksContext } from "~/ui/grouped-networks-context"; -export type HeaderEntityHighlightProps = { - groupedNetworks: GroupedNetworkChains; -}; - -export function EntityHeaderSummary({ - groupedNetworks, -}: HeaderEntityHighlightProps) { +export function EntityHeaderSummary() { const routeParams = useParams() as HeadlessRoute; + const groupedNetworks = useGroupedNetworksContext(); const params = parseHeadlessRouteVercelFix(routeParams); diff --git a/apps/web/ui/entity-header/index.tsx b/apps/web/ui/entity-header/index.tsx index e022bc2ab..79f0bbd5b 100644 --- a/apps/web/ui/entity-header/index.tsx +++ b/apps/web/ui/entity-header/index.tsx @@ -5,7 +5,6 @@ import Link from "next/link"; import { EntityHeaderSearchButton } from "./entity-header-search-button"; // utils -import { getGroupedNetworkChains } from "~/lib/grouped-network-chains"; import { cn } from "~/ui/shadcn/utils"; import { EntityHeaderSummary } from "./entity-header-summary"; @@ -15,8 +14,6 @@ type Props = { }; export async function EntityHeader({ networkSlug }: Props) { - const groupedNetworks = await getGroupedNetworkChains(); - return (
Modular Cloud - + {/* Bigger screens */}
- +
); } 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/branded-logo.tsx b/apps/web/ui/header/branded-logo.tsx new file mode 100644 index 000000000..b6bf48f40 --- /dev/null +++ b/apps/web/ui/header/branded-logo.tsx @@ -0,0 +1,31 @@ +"use client"; +import * as React from "react"; + +import { useParams } from "next/navigation"; +import type { HeadlessRoute } from "~/lib/headless-utils"; +import { MCLogo } from "~/ui/mc-logo"; +import { useGroupedNetworksContext } from "~/ui/grouped-networks-context"; + +export function BrandedLogo() { + const params = useParams() as Pick; + const optionGroups = useGroupedNetworksContext(); + + const network = React.useMemo(() => { + const values = Object.values(optionGroups).flat(); + return ( + values.find((network) => network.slug === params.network) ?? values[0] + ); + }, [optionGroups, params.network]); + + return ( +
+ +
+ ); +} diff --git a/apps/web/ui/header/header-search-button.tsx b/apps/web/ui/header/header-search-button.tsx new file mode 100644 index 000000000..851625386 --- /dev/null +++ b/apps/web/ui/header/header-search-button.tsx @@ -0,0 +1,65 @@ +"use client"; + +import * as React from "react"; +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 { Button } from "~/ui/button"; +import { cn } from "~/ui/shadcn/utils"; + +type Props = { + children: React.ReactNode; +}; + +export function HeaderSearchButton({ children }: Props) { + const params = useParams() as Pick; + const allNetworks = useGroupedNetworksContext(); + + const network = React.useMemo(() => { + const values = Object.values(allNetworks).flat(); + return ( + values.find((network) => network.slug === params.network) ?? values[0] + ); + }, [allNetworks, params.network]); + + return ( + + + + ); +} diff --git a/apps/web/ui/header/index.tsx b/apps/web/ui/header/index.tsx new file mode 100644 index 000000000..af38b5e49 --- /dev/null +++ b/apps/web/ui/header/index.tsx @@ -0,0 +1,18 @@ +import "server-only"; +import { BrandedLogo } from "./branded-logo"; +import { HeaderSearchButton } from "./header-search-button"; + +export async function Header() { + return ( +
+ + + Explore + + / + + +
+
+ ); +} diff --git a/apps/web/app/api/og/components/mc-logo.tsx b/apps/web/ui/mc-logo/index.tsx similarity index 100% rename from apps/web/app/api/og/components/mc-logo.tsx rename to apps/web/ui/mc-logo/index.tsx diff --git a/apps/web/ui/search-options-context/index.tsx b/apps/web/ui/search-options-context/index.tsx deleted file mode 100644 index 182aa10be..000000000 --- a/apps/web/ui/search-options-context/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -"use client"; - -import * as React from "react"; -import type { GroupedNetworkChains } from "~/lib/grouped-network-chains"; - -interface Props { - children: React.ReactNode; - value: GroupedNetworkChains; -} - -export function SearchOptionProvider({ children, value }: Props) { - return ( - - {children} - - ); -} - -type SearchOptionContextType = GroupedNetworkChains; - -const SearchOptionContext = React.createContext( - null, -); - -export function useSearchOptionsContext() { - const contextValue = React.use(SearchOptionContext); - if (!contextValue) { - throw new Error("Should provide the value of the network chains"); - } - return contextValue; -} diff --git a/apps/web/ui/search/integration-grid-view.tsx b/apps/web/ui/search/integration-grid-view.tsx index aa04a0aa0..633b73563 100644 --- a/apps/web/ui/search/integration-grid-view.tsx +++ b/apps/web/ui/search/integration-grid-view.tsx @@ -14,7 +14,7 @@ import type { import { FancyCheck } from "~/ui/icons"; import { Tooltip } from "~/ui/tooltip"; import { useNetworkStatuses } from "./use-network-status"; -import { useSearchOptionsContext } from "~/ui/search-options-context"; +import { useGroupedNetworksContext } from "~/ui/grouped-networks-context"; import { ALWAYS_ONLINE_NETWORKS } from "~/lib/constants"; interface Props { @@ -165,7 +165,7 @@ const BrandChains = React.memo(function BrandChains({ }: BrandChainsProps) { const groupName = options[0].brandName; - const allNetworkChains = useSearchOptionsContext(); + const allNetworkChains = useGroupedNetworksContext(); const values = allNetworkChains.flat(); const brandEcosystems = options[0].ecosystems ?? []; diff --git a/apps/web/ui/search/search-form.tsx b/apps/web/ui/search/search-form.tsx index b3db83bee..da695d796 100644 --- a/apps/web/ui/search/search-form.tsx +++ b/apps/web/ui/search/search-form.tsx @@ -8,14 +8,14 @@ import { LoadingIndicator } from "~/ui/loading-indicator"; import { useParams, useRouter } from "next/navigation"; import { cn } from "~/ui/shadcn/utils"; import { DEFAULT_BRAND_COLOR } from "~/lib/constants"; -import { useSearchOptionsContext } from "~/ui/search-options-context"; +import { useGroupedNetworksContext } from "~/ui/grouped-networks-context"; export function SearchForm() { const params = useParams(); const router = useRouter(); const [isPending, startTransition] = React.useTransition(); - const optionGroups = useSearchOptionsContext(); + const optionGroups = useGroupedNetworksContext(); const network = React.useMemo(() => { const values = optionGroups.flat(); From 7a11bd08f4570ee5a7ed6215b42abe2276bf4471 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 02:58:32 +0100 Subject: [PATCH 17/57] =?UTF-8?q?=F0=9F=8D=B1=20add=20new=20icons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/ui/icon-svgs/ArrowBottomRight.svg | 3 +++ apps/web/ui/icon-svgs/ArrowTopRight.svg | 3 +++ apps/web/ui/icon-svgs/Trends.svg | 3 +++ apps/web/ui/icons/ArrowBottomRight.tsx | 19 +++++++++++++++++++ apps/web/ui/icons/ArrowTopRight.tsx | 19 +++++++++++++++++++ apps/web/ui/icons/Trends.tsx | 19 +++++++++++++++++++ apps/web/ui/icons/index.ts | 3 +++ 7 files changed, 69 insertions(+) create mode 100644 apps/web/ui/icon-svgs/ArrowBottomRight.svg create mode 100644 apps/web/ui/icon-svgs/ArrowTopRight.svg create mode 100644 apps/web/ui/icon-svgs/Trends.svg create mode 100644 apps/web/ui/icons/ArrowBottomRight.tsx create mode 100644 apps/web/ui/icons/ArrowTopRight.tsx create mode 100644 apps/web/ui/icons/Trends.tsx 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/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/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/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/index.ts b/apps/web/ui/icons/index.ts index 5fc770cd0..7c3e7a85c 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"; @@ -86,6 +88,7 @@ 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 Trends } from "./Trends"; export { default as UsdCoin } from "./UsdCoin"; export { default as UserOff } from "./UserOff"; export { default as UserOn } from "./UserOn"; From 46ead98b35010d734e49bb65e740cde368486a22 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 28 Feb 2024 02:58:54 +0100 Subject: [PATCH 18/57] =?UTF-8?q?=F0=9F=92=84=20token-prices=20component?= =?UTF-8?q?=20added?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/app/api/token-prices/[token]/route.ts | 17 +++ apps/web/lib/cache-keys.ts | 1 + apps/web/lib/grouped-network-chains.ts | 2 + apps/web/ui/header/header-search-button.tsx | 6 +- apps/web/ui/header/index.tsx | 15 ++- apps/web/ui/token-prices/index.tsx | 100 ++++++++++++++++++ 6 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 apps/web/app/api/token-prices/[token]/route.ts create mode 100644 apps/web/ui/token-prices/index.tsx diff --git a/apps/web/app/api/token-prices/[token]/route.ts b/apps/web/app/api/token-prices/[token]/route.ts new file mode 100644 index 000000000..bebe9c62f --- /dev/null +++ b/apps/web/app/api/token-prices/[token]/route.ts @@ -0,0 +1,17 @@ +import { NextResponse } from "next/server"; + +export async function GET( + request: Request, + ctx: { params: { token: string } }, +) { + // TODO : modify with actual calls when the API is ready + return NextResponse.json({ + value: Math.random() * 100, + growth: { + percent: Math.random() * 5, + slope: Math.random() > 0.5 ? "increasing" : "decreasing", + }, + }); +} + +export const runtime = "edge"; diff --git a/apps/web/lib/cache-keys.ts b/apps/web/lib/cache-keys.ts index d5831c3d7..599ec1ca9 100644 --- a/apps/web/lib/cache-keys.ts +++ b/apps/web/lib/cache-keys.ts @@ -52,4 +52,5 @@ export const CACHE_KEYS = { context?.endTime?.toString() ?? "undefined", ], }, + token: (name: string) => ["TOKEN", name], } as const; diff --git a/apps/web/lib/grouped-network-chains.ts b/apps/web/lib/grouped-network-chains.ts index 37270f18f..f3464b3ea 100644 --- a/apps/web/lib/grouped-network-chains.ts +++ b/apps/web/lib/grouped-network-chains.ts @@ -28,6 +28,7 @@ export const getGroupedNetworkChains = cache( accountId: currentNetwork.accountId, ecosystems: currentNetwork.config.ecosystems, brandCSSGradient: currentNetwork.config.cssGradient, + token: currentNetwork.config.token, })); return arrayGroupByTo2DArray(options, "accountId"); @@ -50,4 +51,5 @@ export type NetworkChain = { slug: string; ecosystems: string[]; brandCSSGradient: string; + token: SingleNetwork["config"]["token"]; }; diff --git a/apps/web/ui/header/header-search-button.tsx b/apps/web/ui/header/header-search-button.tsx index 851625386..d8989a4f2 100644 --- a/apps/web/ui/header/header-search-button.tsx +++ b/apps/web/ui/header/header-search-button.tsx @@ -11,9 +11,10 @@ import { cn } from "~/ui/shadcn/utils"; type Props = { children: React.ReactNode; + className?: string; }; -export function HeaderSearchButton({ children }: Props) { +export function HeaderSearchButton({ children, className }: Props) { const params = useParams() as Pick; const allNetworks = useGroupedNetworksContext(); @@ -36,9 +37,10 @@ export function HeaderSearchButton({ children }: Props) {
- //
- //
- //
- // {logo} - // - //
- //
{children}
- //
+
{children}
- //
- //
+