feat(bridge-ui): add base path config (#1095)

* fix: add base path config to the bridge ui

* fix: remove unused import

* update bridge UI ci build job

* fix: update env.template
This commit is contained in:
Victorien Gauch
2025-06-09 16:13:35 +02:00
committed by GitHub
parent c44218ebcb
commit 81583c8d14
14 changed files with 42 additions and 22 deletions

View File

@@ -61,6 +61,7 @@ jobs:
NEXT_PUBLIC_LIFI_INTEGRATOR_NAME: ${{ secrets.PUBLIC_LIFI_INTEGRATOR_NAME }}
NEXT_PUBLIC_ONRAMPER_API_KEY: ${{ secrets.PUBLIC_ONRAMPER_API_KEY }}
NEXT_PUBLIC_LAYERSWAP_API_KEY: ${{ secrets.PUBLIC_LAYERSWAP_API_KEY }}
NEXT_PUBLIC_ENVIRONMENT: development
- name: Install linux dependencies
run: |

View File

@@ -21,6 +21,9 @@ jobs:
if: github.event.pull_request.head.repo.fork == false
# ~1 min saved vs small
runs-on: gha-runner-scale-set-ubuntu-22.04-amd64-med
strategy:
matrix:
environment: [development, production]
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -36,7 +39,7 @@ jobs:
- name: Set Docker Tag
id: docker-tag
run: echo "DOCKER_TAG=${GITHUB_SHA:0:7}-$(date +%s)-bridge-ui-${{ steps.package-version.outputs.current-version }}" | tee $GITHUB_ENV
run: echo "DOCKER_TAG=${GITHUB_SHA:0:7}-$(date +%s)-bridge-ui-${{ steps.package-version.outputs.current-version }}-${{ matrix.environment }}" | tee $GITHUB_ENV
- name: Login to Docker Repository
if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }}
@@ -59,6 +62,7 @@ jobs:
tags: consensys/linea-bridge-ui:${{ env.DOCKER_TAG }}
build-args: |
ENV_FILE=./bridge-ui/.env.production
NEXT_PUBLIC_ENVIRONMENT=${{ env.NEXT_PUBLIC_ENVIRONMENT }}
NEXT_PUBLIC_WALLET_CONNECT_ID=${{ env.NEXT_PUBLIC_WALLET_CONNECT_ID }}
NEXT_PUBLIC_INFURA_ID=${{ env.NEXT_PUBLIC_INFURA_ID }}
NEXT_PUBLIC_QUICKNODE_ID=${{ env.NEXT_PUBLIC_QUICKNODE_ID }}
@@ -78,6 +82,7 @@ jobs:
NEXT_PUBLIC_LIFI_INTEGRATOR_NAME: ${{ secrets.PUBLIC_LIFI_INTEGRATOR_NAME }}
NEXT_PUBLIC_ONRAMPER_API_KEY: ${{ secrets.PUBLIC_ONRAMPER_API_KEY }}
NEXT_PUBLIC_LAYERSWAP_API_KEY: ${{ secrets.PUBLIC_LAYERSWAP_API_KEY }}
NEXT_PUBLIC_ENVIRONMENT: ${{ matrix.environment }}
test-build:
if: github.event.pull_request.head.repo.fork == true

View File

@@ -31,6 +31,8 @@ NEXT_PUBLIC_LAYERSWAP_API_KEY=<LAYERSWAP_API_KEY>
NEXT_PUBLIC_IS_CCTP_ENABLED=true
NEXT_PUBLIC_ENVIRONMENT=development
E2E_TEST_PRIVATE_KEY=<YOUR_PRIVATE_KEY>
NEXT_PUBLIC_STORAGE_MIN_VERSION="4"

View File

@@ -14,6 +14,7 @@ ARG NEXT_PUBLIC_LIFI_API_KEY
ARG NEXT_PUBLIC_LIFI_INTEGRATOR_NAME
ARG NEXT_PUBLIC_ONRAMPER_API_KEY
ARG NEXT_PUBLIC_LAYERSWAP_API_KEY
ARG NEXT_PUBLIC_ENVIRONMENT
ENV NEXT_PUBLIC_WALLET_CONNECT_ID=$NEXT_PUBLIC_WALLET_CONNECT_ID
ENV NEXT_PUBLIC_INFURA_ID=$NEXT_PUBLIC_INFURA_ID
@@ -23,6 +24,7 @@ ENV NEXT_PUBLIC_LIFI_API_KEY=$NEXT_PUBLIC_LIFI_API_KEY
ENV NEXT_PUBLIC_LIFI_INTEGRATOR_NAME=$NEXT_PUBLIC_LIFI_INTEGRATOR_NAME
ENV NEXT_PUBLIC_ONRAMPER_API_KEY=$NEXT_PUBLIC_ONRAMPER_API_KEY
ENV NEXT_PUBLIC_LAYERSWAP_API_KEY=$NEXT_PUBLIC_LAYERSWAP_API_KEY
ENV NEXT_PUBLIC_ENVIRONMENT=$NEXT_PUBLIC_ENVIRONMENT
ARG ENV_FILE

View File

@@ -5,6 +5,7 @@ declare global {
E2E_TEST_PRIVATE_KEY: string;
E2E_TEST_WALLET_PASSWORD: string;
NEXT_PUBLIC_INFURA_ID: string;
NEXT_PUBLIC_BASE_PATH: string;
}
}
}

View File

@@ -1,7 +1,14 @@
const isProd = process.env.NEXT_PUBLIC_ENVIRONMENT === "production";
const basePath = isProd ? "/hub/bridge" : "";
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
reactStrictMode: true,
basePath,
env: {
NEXT_PUBLIC_BASE_PATH: basePath,
},
images: {
remotePatterns: [
{

View File

@@ -8,7 +8,9 @@ export default function BridgeMode() {
const token = useFormStore((state) => state.token);
const label = token.bridgeProvider === BridgeProvider.NATIVE ? "Native bridge" : "CCTP";
const logoSrc =
token.bridgeProvider === BridgeProvider.NATIVE ? "/images/logo/linea-rounded.svg" : "/images/logo/cctp.svg";
token.bridgeProvider === BridgeProvider.NATIVE
? `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/linea-rounded.svg`
: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/cctp.svg`;
return (
<div className={styles.container}>

View File

@@ -159,7 +159,7 @@ export const MENUS = [
title: "x",
description: "",
file: {
url: "/images/logo/header/x.svg",
url: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/header/x.svg`,
details: {
size: 389,
image: {
@@ -185,7 +185,7 @@ export const MENUS = [
title: "farcaster-final",
description: "",
file: {
url: "/images/logo/header/farcaster-final.svg",
url: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/header/farcaster-final.svg`,
details: {
size: 925,
image: {
@@ -211,7 +211,7 @@ export const MENUS = [
title: "discord",
description: "",
file: {
url: "/images/logo/header/discord.svg",
url: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/header/discord.svg`,
details: {
size: 1346,
image: {
@@ -237,7 +237,7 @@ export const MENUS = [
title: "youtube",
description: "",
file: {
url: "/images/logo/header/youtube.svg",
url: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/header/youtube.svg`,
details: {
size: 1031,
image: {
@@ -263,7 +263,7 @@ export const MENUS = [
title: "x",
description: "",
file: {
url: "/images/logo/header/x.svg",
url: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/header/x.svg`,
details: {
size: 389,
image: {

View File

@@ -39,7 +39,7 @@ function CommonLayout({ children, pathname }: { children: React.ReactNode; pathn
<div>
<Image
className="left-illustration"
src="/images/illustration/illustration-left.svg"
src={`${process.env.NEXT_PUBLIC_BASE_PATH}/images/illustration/illustration-left.svg`}
role="presentation"
alt="illustration left"
width={300}
@@ -48,7 +48,7 @@ function CommonLayout({ children, pathname }: { children: React.ReactNode; pathn
/>
<Image
className="right-illustration"
src="/images/illustration/illustration-right.svg"
src={`${process.env.NEXT_PUBLIC_BASE_PATH}/images/illustration/illustration-right.svg`}
role="presentation"
alt="illustration right"
width={610}

View File

@@ -44,7 +44,7 @@ const modalData: Record<VisitedModalType, FirstTimeModalDataType> = {
btnText: "Start bridging now",
extraText: "Ready to bridge?",
image: {
src: "/images/illustration/bridge-first-time-modal-illustration.svg",
src: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/illustration/bridge-first-time-modal-illustration.svg`,
width: 128,
height: 179,
},
@@ -61,7 +61,7 @@ const modalData: Record<VisitedModalType, FirstTimeModalDataType> = {
btnText: "Start bridging now",
extraText: "Ready to bridge?",
image: {
src: "/images/illustration/bridge-first-time-modal-illustration.svg",
src: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/illustration/bridge-first-time-modal-illustration.svg`,
width: 128,
height: 179,
},
@@ -78,7 +78,7 @@ const modalData: Record<VisitedModalType, FirstTimeModalDataType> = {
],
btnText: "Buy tokens now",
image: {
src: "/images/illustration/buy-first-time-modal-illustration.svg",
src: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/illustration/buy-first-time-modal-illustration.svg`,
width: 157,
height: 167,
},

View File

@@ -23,7 +23,7 @@ export default function TopBanner({ text, href }: Props) {
<div className={styles["banner-wrapper"]}>
<Image
className={styles["left-illustration"]}
src={"/images/illustration/banner/left.svg"}
src={`${process.env.NEXT_PUBLIC_BASE_PATH}/images/illustration/banner/left.svg`}
role="presentation"
alt="banner illustration left"
width={0}
@@ -40,7 +40,7 @@ export default function TopBanner({ text, href }: Props) {
<CloseIcon onClick={handleClose} className={styles["close-icon"]} />
<Image
className={styles["right-illustration"]}
src={"/images/illustration/banner/right.svg"}
src={`${process.env.NEXT_PUBLIC_BASE_PATH}/images/illustration/banner/right.svg`}
role="presentation"
alt="banner illustration right"
width={0}

View File

@@ -4,7 +4,7 @@ import { configSchema, Config } from "./config.schema";
export const config: Config = {
chains: {
1: {
iconPath: "/images/logo/ethereum-rounded.svg",
iconPath: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/ethereum-rounded.svg`,
messageServiceAddress: getAddress(process.env.NEXT_PUBLIC_MAINNET_L1_MESSAGE_SERVICE ?? ""),
tokenBridgeAddress: getAddress(process.env.NEXT_PUBLIC_MAINNET_L1_TOKEN_BRIDGE ?? ""),
gasLimitSurplus: process.env.NEXT_PUBLIC_MAINNET_DEFAULT_GAS_LIMIT_SURPLUS
@@ -18,7 +18,7 @@ export const config: Config = {
cctpMessageTransmitterV2Address: getAddress("0x81D40F21F12A8F0E3252Bccb954D722d4c464B64"),
},
59144: {
iconPath: "/images/logo/linea-rounded.svg",
iconPath: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/linea-rounded.svg`,
messageServiceAddress: getAddress(process.env.NEXT_PUBLIC_MAINNET_LINEA_MESSAGE_SERVICE ?? ""),
tokenBridgeAddress: getAddress(process.env.NEXT_PUBLIC_MAINNET_LINEA_TOKEN_BRIDGE ?? ""),
gasLimitSurplus: process.env.NEXT_PUBLIC_MAINNET_DEFAULT_GAS_LIMIT_SURPLUS
@@ -32,7 +32,7 @@ export const config: Config = {
cctpMessageTransmitterV2Address: getAddress("0x81D40F21F12A8F0E3252Bccb954D722d4c464B64"),
},
11155111: {
iconPath: "/images/logo/ethereum-rounded.svg",
iconPath: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/ethereum-rounded.svg`,
messageServiceAddress: getAddress(process.env.NEXT_PUBLIC_SEPOLIA_L1_MESSAGE_SERVICE ?? ""),
tokenBridgeAddress: getAddress(process.env.NEXT_PUBLIC_SEPOLIA_L1_TOKEN_BRIDGE ?? ""),
gasLimitSurplus: process.env.NEXT_PUBLIC_SEPOLIA_DEFAULT_GAS_LIMIT_SURPLUS
@@ -46,7 +46,7 @@ export const config: Config = {
cctpMessageTransmitterV2Address: getAddress("0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275"),
},
59141: {
iconPath: "/images/logo/linea-sepolia.svg",
iconPath: `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/linea-sepolia.svg`,
messageServiceAddress: getAddress(process.env.NEXT_PUBLIC_SEPOLIA_LINEA_MESSAGE_SERVICE ?? ""),
tokenBridgeAddress: getAddress(process.env.NEXT_PUBLIC_SEPOLIA_LINEA_TOKEN_BRIDGE ?? ""),
gasLimitSurplus: process.env.NEXT_PUBLIC_SEPOLIA_DEFAULT_GAS_LIMIT_SURPLUS

View File

@@ -61,7 +61,7 @@ export async function validateTokenURI(url: string): Promise<string> {
await fetch(url);
return url;
} catch (error) {
return "/images/logo/noTokenLogo.svg";
return `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/noTokenLogo.svg`;
}
}

View File

@@ -57,12 +57,12 @@ export const getChainNetworkLayer = (chainId: number) => {
export const getChainLogoPath = (chainId: number) => {
switch (chainId) {
case linea.id:
return "/images/logo/linea-rounded.svg";
return `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/linea-rounded.svg`;
case lineaSepolia.id:
return "/images/logo/linea-sepolia.svg";
return `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/linea-sepolia.svg`;
case mainnet.id:
case sepolia.id:
return "/images/logo/ethereum-rounded.svg";
return `${process.env.NEXT_PUBLIC_BASE_PATH}/images/logo/ethereum-rounded.svg`;
default:
return "";
}