mirror of
https://github.com/luxfi/explore.git
synced 2026-07-27 03:13:50 +00:00
brand: remove all Blockscout branding, replace with Lux Explorer
- Gas tracker FAQ: Blockscout → Lux Explorer - Chain config web3/chains.ts: explorer name → Lux Explorer - Auth screens: Blockscout account → Lux account - Contract verification: Blockscout supports → Lux Explorer supports - API docs: Blockscout core API → Lux Explorer Core API - Rewards/merits: Blockscout Merits → Lux Explorer Rewards - Marketplace disclaimer and integration icons - Address verification: help@blockscout.com → support@lux.network - Chart export filenames: Blockscout chart/stats → Lux Explorer - OTEL service name: blockscout_frontend → lux_explorer_frontend - Dev container: blockscout dev → lux explorer dev
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "blockscout dev",
|
||||
"name": "lux explorer dev",
|
||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
|
||||
"forwardPorts": [ 3000 ],
|
||||
"customizations": {
|
||||
|
||||
@@ -22,7 +22,7 @@ const config: Feature<{
|
||||
title,
|
||||
isEnabled: true,
|
||||
tabs,
|
||||
coreApiSwaggerUrl: getEnvValue('NEXT_PUBLIC_API_SPEC_URL') || `https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml`,
|
||||
coreApiSwaggerUrl: getEnvValue('NEXT_PUBLIC_API_SPEC_URL') || `https://raw.githubusercontent.com/luxfi/explorer-api-swagger/main/swagger.yaml`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import { getEnvValue, getExternalAssetFilePath } from './utils';
|
||||
const defaultImageUrl = '/static/og_image.png';
|
||||
|
||||
const meta = Object.freeze({
|
||||
// Lux fork: disable Blockscout branding by default
|
||||
promoteBlockscoutInTitle: getEnvValue('NEXT_PUBLIC_PROMOTE_BLOCKSCOUT_IN_TITLE') === 'true' ? true : false,
|
||||
og: {
|
||||
description: getEnvValue('NEXT_PUBLIC_OG_DESCRIPTION') || '',
|
||||
imageUrl: app.baseUrl + (getExternalAssetFilePath('NEXT_PUBLIC_OG_IMAGE_URL') || defaultImageUrl),
|
||||
|
||||
@@ -18,7 +18,7 @@ const traceExporter = new OTLPTraceExporter();
|
||||
|
||||
const sdk = new NodeSDK({
|
||||
resource: new Resource({
|
||||
[SEMRESATTRS_SERVICE_NAME]: 'blockscout_frontend',
|
||||
[SEMRESATTRS_SERVICE_NAME]: 'lux_explorer_frontend',
|
||||
[SEMRESATTRS_SERVICE_VERSION]: process.env.NEXT_PUBLIC_GIT_TAG || process.env.NEXT_PUBLIC_GIT_COMMIT_SHA || 'unknown_version',
|
||||
[SEMRESATTRS_SERVICE_INSTANCE_ID]:
|
||||
process.env.NEXT_PUBLIC_APP_INSTANCE ||
|
||||
|
||||
@@ -73,8 +73,8 @@ const RewardsContext = createContext<TRewardsContext>(initialState);
|
||||
|
||||
// Message to sign for the rewards program
|
||||
function getMessageToSign(address: string, nonce: string, isLogin?: boolean, refCode?: string) {
|
||||
const signInText = 'Sign-In for the Blockscout Merits program.';
|
||||
const signUpText = 'Sign-Up for the Blockscout Merits program. I accept Terms of Service: https://merits.blockscout.com/terms. I love capybaras.';
|
||||
const signInText = 'Sign-In for the Lux Explorer Rewards program.';
|
||||
const signUpText = 'Sign-Up for the Lux Explorer Rewards program. I accept Terms of Service: https://merits.blockscout.com/terms. I love capybaras.';
|
||||
const referralText = refCode ? ` Referral code: ${ refCode }` : '';
|
||||
const body = isLogin ? signInText : signUpText + referralText;
|
||||
|
||||
|
||||
@@ -118,7 +118,5 @@ const TEMPLATE_MAP_ENHANCED: Partial<Record<Route['pathname'], string>> = {
|
||||
|
||||
export function make(pathname: Route['pathname'], isEnriched = false) {
|
||||
const template = (isEnriched ? TEMPLATE_MAP_ENHANCED[pathname] : undefined) ?? TEMPLATE_MAP[pathname];
|
||||
const postfix = config.meta.promoteBlockscoutInTitle ? ' | Blockscout' : '';
|
||||
|
||||
return (template + postfix).trim();
|
||||
return template.trim();
|
||||
}
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ const getChainInfo = (
|
||||
},
|
||||
blockExplorers: {
|
||||
'default': {
|
||||
name: 'Blockscout',
|
||||
name: 'Lux Explorer',
|
||||
url: config.app.baseUrl,
|
||||
},
|
||||
},
|
||||
@@ -66,7 +66,7 @@ export const parentChain: Chain | undefined = (() => {
|
||||
},
|
||||
blockExplorers: {
|
||||
'default': {
|
||||
name: 'Blockscout',
|
||||
name: 'Lux Explorer',
|
||||
url: parentChain.baseUrl,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -96,7 +96,7 @@ const ChartMenu = ({
|
||||
})
|
||||
.then((dataUrl) => {
|
||||
const link = document.createElement('a');
|
||||
link.download = `${ title }${ chainPostfix } (Blockscout chart).png`;
|
||||
link.download = `${ title }${ chainPostfix } (Lux Explorer chart).png`;
|
||||
link.href = dataUrl;
|
||||
link.click();
|
||||
link.remove();
|
||||
@@ -113,7 +113,7 @@ const ChartMenu = ({
|
||||
item.dateLabel ?? dayjs(item.date).format('YYYY-MM-DD'),
|
||||
...charts.map((chart) => String(chart.items[index].value)),
|
||||
]);
|
||||
saveAsCsv(headerRows, dataRows, `${ title }${ chainPostfix } (Blockscout stats)`);
|
||||
saveAsCsv(headerRows, dataRows, `${ title }${ chainPostfix } (Lux Explorer stats)`);
|
||||
}, [ charts, title, chainPostfix ]);
|
||||
|
||||
// TS thinks window.navigator.share can't be undefined, but it can
|
||||
|
||||
+12
-157
@@ -1,179 +1,34 @@
|
||||
# Blockscout UI Toolkit
|
||||
# Lux UI Toolkit
|
||||
|
||||
A comprehensive collection of reusable Chakra UI components and theme system for Blockscout's projects. This toolkit provides a consistent design system and UI components to maintain visual consistency across Blockscout applications.
|
||||
A comprehensive collection of reusable UI components and theme system for Lux Network explorer and related applications.
|
||||
|
||||
## Features
|
||||
|
||||
- 🎨 Pre-configured Chakra UI theme with Blockscout's design system
|
||||
- 🧩 Reusable UI components built on Chakra UI
|
||||
- 🌓 Built-in dark mode support
|
||||
- 📱 Responsive and accessible components
|
||||
- 🔍 TypeScript support with proper type definitions
|
||||
- Pre-configured theme with Lux Network's monochrome design system
|
||||
- Reusable UI components built on Chakra UI
|
||||
- Built-in dark mode support
|
||||
- Responsive and accessible components
|
||||
- TypeScript support with proper type definitions
|
||||
|
||||
## Installation
|
||||
|
||||
### Package Installation
|
||||
|
||||
Install the package using your preferred package manager:
|
||||
|
||||
```bash
|
||||
# Using npm
|
||||
npm install @blockscout/ui-toolkit
|
||||
|
||||
# Using yarn
|
||||
yarn add @blockscout/ui-toolkit
|
||||
```
|
||||
|
||||
### Required Dependencies
|
||||
|
||||
Ensure you have the following peer dependencies installed:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@blockscout/ui-toolkit": "latest",
|
||||
"@chakra-ui/react": ">=3.15.0",
|
||||
"@emotion/react": ">=11.14.0",
|
||||
"@uidotdev/usehooks": ">=2.4.1",
|
||||
"d3": ">=7.6.1",
|
||||
"dayjs": ">=1.11.5",
|
||||
"dom-to-image": ">=2.6.0",
|
||||
"es-toolkit": ">=1.39.10",
|
||||
"next": ">=15.2.3",
|
||||
"next-themes": ">=0.4.4",
|
||||
"react": ">=18.3.1",
|
||||
"react-dom": ">=18.3.1",
|
||||
"react-hook-form": ">=7.52.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chakra-ui/cli": ">=3.15.0",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "18.3.12",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"typescript": "5.4.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Theme Setup
|
||||
|
||||
Create a `theme.ts` file in your project and configure the Blockscout theme:
|
||||
|
||||
```tsx
|
||||
// Basic setup
|
||||
import { theme } from '@blockscout/ui-toolkit';
|
||||
export default theme;
|
||||
```
|
||||
|
||||
Or extend the theme with custom overrides:
|
||||
|
||||
```tsx
|
||||
import { createSystem } from '@chakra-ui/react';
|
||||
import { themeConfig } from '@blockscout/ui-toolkit';
|
||||
|
||||
const customOverrides = {
|
||||
// Add your custom theme overrides here
|
||||
theme: {
|
||||
semanticTokens: {
|
||||
colors: {
|
||||
brand: {
|
||||
primary: { value: '#5353D3' }
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default createSystem(themeConfig, customOverrides);
|
||||
```
|
||||
|
||||
### 2. Provider Setup
|
||||
|
||||
Wrap your application with the ChakraProvider:
|
||||
|
||||
```tsx
|
||||
import { ChakraProvider } from '@chakra-ui/react';
|
||||
import { Button } from '@blockscout/ui-toolkit';
|
||||
import theme from './theme';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ChakraProvider theme={theme}>
|
||||
<Button>Click me</Button>
|
||||
</ChakraProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. TypeScript Support
|
||||
|
||||
Add the following script to your `package.json` to generate Chakra UI type definitions:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"chakra:typegen": "chakra typegen ./src/theme.ts"
|
||||
}
|
||||
}
|
||||
npm install @luxfi/ui-toolkit
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Local Development
|
||||
|
||||
1. Clone the repository and install dependencies:
|
||||
```bash
|
||||
# Install dependencies
|
||||
yarn
|
||||
```
|
||||
|
||||
2. Start the development server:
|
||||
```bash
|
||||
# Start development server
|
||||
yarn dev
|
||||
```
|
||||
|
||||
3. Build the package:
|
||||
```bash
|
||||
# Build
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Publishing
|
||||
|
||||
#### Manual Publishing
|
||||
|
||||
1. Update the package version:
|
||||
```bash
|
||||
npm version <version-tag>
|
||||
```
|
||||
|
||||
2. Build the package:
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
3. Publish to NPM:
|
||||
```bash
|
||||
npm publish --access public
|
||||
```
|
||||
|
||||
#### Automated Publishing
|
||||
|
||||
Use the `toolkit-npm-publisher.yml` GitHub Actions workflow for automated publishing.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions! Please follow these steps:
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes
|
||||
4. Submit a pull request
|
||||
|
||||
## Support
|
||||
|
||||
For issues, feature requests, or questions, please open an issue in the repository.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the GNU General Public License v3.
|
||||
This project is licensed under the GNU General Public License v3.
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
{
|
||||
"name": "@blockscout/ui-toolkit",
|
||||
"name": "@luxfi/ui-toolkit",
|
||||
"version": "2.4.0-alpha",
|
||||
"description": "A comprehensive collection of reusable Chakra UI components and theme system for Blockscout's projects",
|
||||
"description": "A comprehensive collection of reusable UI components and theme system for Lux Network explorer",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"license": "GPL-3.0-only",
|
||||
"author": "Blockscout Team",
|
||||
"author": "Lux Industries Inc",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/blockscout/frontend.git",
|
||||
"url": "https://github.com/luxfi/explore.git",
|
||||
"directory": "toolkit/package"
|
||||
},
|
||||
"homepage": "https://github.com/blockscout/frontend/tree/main/toolkit/package",
|
||||
"homepage": "https://github.com/luxfi/explore/tree/main/toolkit/package",
|
||||
"bugs": {
|
||||
"url": "https://github.com/blockscout/frontend/issues"
|
||||
"url": "https://github.com/luxfi/explore/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"blockscout",
|
||||
"lux",
|
||||
"explorer",
|
||||
"ui",
|
||||
"components",
|
||||
"chakra-ui",
|
||||
"react",
|
||||
"typescript",
|
||||
"design-system"
|
||||
|
||||
@@ -152,7 +152,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
|
||||
);
|
||||
})();
|
||||
|
||||
const contactUsLink = <span>contact us <Link href="mailto:help@blockscout.com" rel="noopener noreferrer">help@blockscout.com</Link></span>;
|
||||
const contactUsLink = <span>contact us <Link href="mailto:support@lux.network" rel="noopener noreferrer">support@lux.network</Link></span>;
|
||||
|
||||
const rootError = (() => {
|
||||
switch (formState.errors.root?.type) {
|
||||
@@ -198,8 +198,8 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
|
||||
<form noValidate onSubmit={ onSubmit }>
|
||||
{ rootError && <Alert status="warning" mb={ 6 }>{ rootError }</Alert> }
|
||||
<Box mb={ 8 }>
|
||||
<span>Please select the address to sign and copy the message and sign it using the Blockscout message provider of your choice. </span>
|
||||
<Link href="https://docs.blockscout.com/using-blockscout/my-account/verified-addresses/copy-and-sign-message" external noIcon>
|
||||
<span>Please select the address to sign and copy the message and sign it using the Lux Explorer message provider of your choice. </span>
|
||||
<Link href="https://docs.lux.network/using-lux-explorer/my-account/verified-addresses/copy-and-sign-message" external noIcon>
|
||||
Additional instructions
|
||||
</Link>
|
||||
<span>. If you do not see your address here but are sure that you are the owner of the contract, kindly </span>
|
||||
|
||||
@@ -8,7 +8,7 @@ const EthRpcApi = () => {
|
||||
<Box>
|
||||
<Text>
|
||||
In addition to the custom RPC endpoints documented here,
|
||||
the Blockscout ETH RPC API supports 3 methods in the exact format specified for Ethereum nodes,
|
||||
the Lux Explorer ETH RPC API supports 3 methods in the exact format specified for Ethereum nodes,
|
||||
ee the Ethereum JSON-RPC Specification for more details.
|
||||
</Text>
|
||||
<Link href="https://docs.blockscout.com/devs/apis/rpc/eth-rpc" external mt={ 6 }>View examples</Link>
|
||||
|
||||
+4
-4
@@ -20,8 +20,8 @@ const getMicroserviceSwaggerUrl = (api: ApiPropsBase) => `${ api.endpoint }${ ap
|
||||
|
||||
export const REST_API_SECTIONS = [
|
||||
feature.isEnabled && {
|
||||
id: 'blockscout-core-api',
|
||||
title: 'Blockscout core API',
|
||||
id: 'lux-core-api',
|
||||
title: 'Lux Explorer Core API',
|
||||
swagger: {
|
||||
url: feature.coreApiSwaggerUrl,
|
||||
requestInterceptor: (req: SwaggerRequest) => {
|
||||
@@ -29,8 +29,8 @@ export const REST_API_SECTIONS = [
|
||||
return req;
|
||||
}
|
||||
|
||||
const DEFAULT_SERVER = 'blockscout.com/poa/core';
|
||||
const DEFAULT_SERVER_NEW = 'eth.blockscout.com';
|
||||
const DEFAULT_SERVER = 'api.lux.network';
|
||||
const DEFAULT_SERVER_NEW = 'api.lux.network';
|
||||
|
||||
if (!req.loadSpec) {
|
||||
const newUrl = new URL(
|
||||
|
||||
@@ -80,7 +80,7 @@ const ContractVerificationFieldMethod = ({ methods }: Props) => {
|
||||
|
||||
const tooltipContent = (
|
||||
<Box>
|
||||
<span>Currently, Blockscout supports { methods.length } methods:</span>
|
||||
<span>Currently, Lux Explorer supports { methods.length } methods:</span>
|
||||
<List.Root as="ol" pl={ 5 }>
|
||||
{ methods.map(renderPopoverListItem) }
|
||||
</List.Root>
|
||||
@@ -90,7 +90,7 @@ const ContractVerificationFieldMethod = ({ methods }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<Heading level="2" mt={{ base: 10, lg: 6 }} gridColumn={{ lg: '1 / 3' }}>
|
||||
Currently, Blockscout supports { methods.length }{ nbsp }contract verification methods
|
||||
Currently, Lux Explorer supports { methods.length }{ nbsp }contract verification methods
|
||||
<Hint
|
||||
label={ tooltipContent }
|
||||
tooltipProps={{ interactive: true, contentProps: { textAlign: 'left' } }}
|
||||
|
||||
@@ -16,16 +16,16 @@ const FAQ_ITEMS = [
|
||||
{
|
||||
question: `How can I check ${ config.chain.name } gas fees?`,
|
||||
// eslint-disable-next-line max-len
|
||||
answer: `You can easily check live ${ config.chain.name } gas fees on Blockscout by visiting our gas tracker. It displays current gas fees in ${ currencyUnits.gwei } for all ${ config.chain.name } transactions.`,
|
||||
answer: `You can easily check live ${ config.chain.name } gas fees on Lux Explorer by visiting our gas tracker. It displays current gas fees in ${ currencyUnits.gwei } for all ${ config.chain.name } transactions.`,
|
||||
},
|
||||
{
|
||||
question: `What is the average gas fee for ${ config.chain.name } transactions?`,
|
||||
// eslint-disable-next-line max-len
|
||||
answer: `The average gas fee for ${ config.chain.name } transactions depends on network congestion and transaction complexity. Blockscout provides real-time gas fee estimations to help users make informed decisions.`,
|
||||
answer: `The average gas fee for ${ config.chain.name } transactions depends on network congestion and transaction complexity. Lux Explorer provides real-time gas fee estimations to help users make informed decisions.`,
|
||||
},
|
||||
{
|
||||
question: 'How does Blockscout calculate gas fees?',
|
||||
answer: 'Blockscout calculates gas fees based on the average price of gas fees spent for the last 200 blocks.',
|
||||
question: 'How does Lux Explorer calculate gas fees?',
|
||||
answer: 'Lux Explorer calculates gas fees based on the average price of gas fees spent for the last 200 blocks.',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ const MarketplaceAppIntegrationIcon = ({ external, internalWallet }: Props) => {
|
||||
const [ icon, iconColor, text, boxSize ] = React.useMemo(() => {
|
||||
let icon: IconName = 'integration/partial';
|
||||
let color = 'icon.secondary';
|
||||
let text = 'This app opens in Blockscout without Blockscout wallet functionality. Use your external web3 wallet to connect directly to this application';
|
||||
let text = 'This app opens in Lux Explorer without wallet functionality. Use your external web3 wallet to connect directly to this application';
|
||||
let boxSize = 5;
|
||||
|
||||
if (external) {
|
||||
@@ -24,7 +24,7 @@ const MarketplaceAppIntegrationIcon = ({ external, internalWallet }: Props) => {
|
||||
} else if (internalWallet) {
|
||||
icon = 'integration/full';
|
||||
color = 'green.500';
|
||||
text = 'This app opens in Blockscout and your Blockscout wallet connects automatically';
|
||||
text = 'This app opens in Lux Explorer and your Lux Explorer wallet connects automatically';
|
||||
}
|
||||
|
||||
return [ icon, color, text, boxSize ];
|
||||
|
||||
@@ -35,7 +35,7 @@ const MarketplaceDisclaimerModal = ({ isOpen, onClose, appId }: Props) => {
|
||||
|
||||
<DialogBody>
|
||||
<Text color={{ _light: 'gray.800', _dark: 'whiteAlpha.800' }}>
|
||||
You are now accessing a third-party app. Blockscout does not own, control, maintain, or audit 3rd party apps,{ ' ' }
|
||||
You are now accessing a third-party app. Lux Explorer does not own, control, maintain, or audit 3rd party apps,{ ' ' }
|
||||
and is not liable for any losses associated with these interactions. Please do so at your own risk.
|
||||
<br/><br/>
|
||||
By clicking continue, you agree that you understand the risks and have read the Disclaimer.
|
||||
|
||||
+225
-118
@@ -40,8 +40,9 @@ const L1_EXPLORER_URLS: Readonly<Record<string, string>> = {
|
||||
Pars: 'https://explore-pars.lux.network',
|
||||
};
|
||||
|
||||
const STAT_CARD_BG = { _light: 'gray.50', _dark: 'whiteAlpha.50' };
|
||||
const CHAIN_CARD_HOVER = { _light: 'gray.50', _dark: 'whiteAlpha.100' };
|
||||
const CARD_BG = { _light: 'gray.50', _dark: 'whiteAlpha.50' };
|
||||
const CARD_HOVER = { _light: 'gray.100', _dark: 'whiteAlpha.100' };
|
||||
const CARD_BORDER = '1px solid';
|
||||
|
||||
function formatStake(nanoLux: bigint): string {
|
||||
const lux = Number(nanoLux) / Math.pow(10, LUX_DECIMALS);
|
||||
@@ -50,56 +51,60 @@ function formatStake(nanoLux: bigint): string {
|
||||
return lux.toFixed(0);
|
||||
}
|
||||
|
||||
interface NetworkStatProps {
|
||||
// ── Hero metric (compact inline stat) ──
|
||||
|
||||
interface MetricProps {
|
||||
readonly label: string;
|
||||
readonly value: string;
|
||||
readonly isLoading: boolean;
|
||||
}
|
||||
|
||||
const NetworkStat = ({ label, value, isLoading }: NetworkStatProps) => (
|
||||
<Box textAlign="center">
|
||||
const Metric = ({ label, value, isLoading }: MetricProps) => (
|
||||
<Flex direction="column" align="center" px={ 3 }>
|
||||
<Skeleton loading={ isLoading }>
|
||||
<Text fontSize={{ base: 'lg', lg: '2xl' }} fontWeight={ 700 } color="text.primary">
|
||||
<Text fontSize="lg" fontWeight={ 700 } fontFamily="mono" color="text.primary" lineHeight="1.2">
|
||||
{ value }
|
||||
</Text>
|
||||
</Skeleton>
|
||||
<Text fontSize="xs" color="text.secondary" fontWeight={ 500 } mt={ 0.5 }>
|
||||
<Text fontSize="2xs" color="text.secondary" fontWeight={ 500 } mt={ 0.5 } textTransform="uppercase" letterSpacing="0.05em">
|
||||
{ label }
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
interface ChainCardProps {
|
||||
// ── Chain row (compact, for sidebar) ──
|
||||
|
||||
interface ChainRowProps {
|
||||
readonly name: string;
|
||||
readonly fullName: string;
|
||||
readonly vm: string;
|
||||
readonly href: string | undefined;
|
||||
readonly tier?: string;
|
||||
}
|
||||
|
||||
const ChainCard = ({ name, fullName, vm, href }: ChainCardProps) => {
|
||||
const ChainRow = ({ name, fullName, vm, href, tier }: ChainRowProps) => {
|
||||
const content = (
|
||||
<Flex
|
||||
align="center"
|
||||
justify="space-between"
|
||||
p={ 3 }
|
||||
py={ 2 }
|
||||
px={ 3 }
|
||||
borderRadius="md"
|
||||
border="1px solid"
|
||||
borderColor="border.divider"
|
||||
cursor={ href ? 'pointer' : 'default' }
|
||||
_hover={ href ? { bg: CHAIN_CARD_HOVER } : undefined }
|
||||
_hover={ href ? { bg: CARD_HOVER } : undefined }
|
||||
transition="background 0.15s"
|
||||
>
|
||||
<Box>
|
||||
<Flex align="center" gap={ 2 }>
|
||||
<Text fontWeight={ 600 } color="text.primary" fontSize="sm">
|
||||
{ name }
|
||||
</Text>
|
||||
<Text fontSize="xs" color="text.secondary">
|
||||
<Text fontSize="xs" color="text.secondary" display={{ base: 'none', lg: 'inline' }}>
|
||||
{ fullName }
|
||||
</Text>
|
||||
</Box>
|
||||
<Flex align="center" gap={ 2 }>
|
||||
</Flex>
|
||||
<Flex align="center" gap={ 1.5 }>
|
||||
{ tier && <Tag size="sm" variant="subtle">{ tier }</Tag> }
|
||||
<Tag size="sm" variant="subtle">{ vm }</Tag>
|
||||
{ href && <Text color="text.secondary" fontSize="sm">{ '\u2192' }</Text> }
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
@@ -110,11 +115,13 @@ const ChainCard = ({ name, fullName, vm, href }: ChainCardProps) => {
|
||||
return content;
|
||||
};
|
||||
|
||||
interface L1ChainCardProps {
|
||||
// ── L1 Chain row ──
|
||||
|
||||
interface L1ChainRowProps {
|
||||
readonly chain: PChainBlockchain;
|
||||
}
|
||||
|
||||
const L1ChainCard = ({ chain }: L1ChainCardProps) => {
|
||||
const L1ChainRow = ({ chain }: L1ChainRowProps) => {
|
||||
const explorerUrl = L1_EXPLORER_URLS[chain.name];
|
||||
const slug = chain.name.toLowerCase();
|
||||
|
||||
@@ -122,25 +129,24 @@ const L1ChainCard = ({ chain }: L1ChainCardProps) => {
|
||||
<Flex
|
||||
align="center"
|
||||
justify="space-between"
|
||||
p={ 3 }
|
||||
py={ 2 }
|
||||
px={ 3 }
|
||||
borderRadius="md"
|
||||
border="1px solid"
|
||||
borderColor="border.divider"
|
||||
cursor="pointer"
|
||||
_hover={{ bg: CHAIN_CARD_HOVER }}
|
||||
_hover={{ bg: CARD_HOVER }}
|
||||
transition="background 0.15s"
|
||||
>
|
||||
<Box>
|
||||
<Flex align="center" gap={ 2 }>
|
||||
<Text fontWeight={ 600 } color="text.primary" fontSize="sm">
|
||||
{ chain.name }
|
||||
</Text>
|
||||
<Text fontSize="xs" color="text.secondary" fontFamily="mono">
|
||||
{ chain.id.slice(0, 10) }...
|
||||
<Text fontSize="xs" color="text.secondary" fontFamily="mono" display={{ base: 'none', lg: 'inline' }}>
|
||||
{ chain.id.slice(0, 8) }...
|
||||
</Text>
|
||||
</Box>
|
||||
<Flex align="center" gap={ 2 }>
|
||||
</Flex>
|
||||
<Flex align="center" gap={ 1.5 }>
|
||||
<Tag size="sm" variant="subtle">L1</Tag>
|
||||
<Text color="text.secondary" fontSize="sm">{ '\u2192' }</Text>
|
||||
<Text color="text.secondary" fontSize="xs">{ '\u2192' }</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
@@ -148,12 +154,48 @@ const L1ChainCard = ({ chain }: L1ChainCardProps) => {
|
||||
if (explorerUrl) {
|
||||
return <Link href={ explorerUrl } variant="plain" target="_blank">{ content }</Link>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={ `/chains/${ slug }` } variant="plain">{ content }</Link>
|
||||
);
|
||||
return <Link href={ `/chains/${ slug }` } variant="plain">{ content }</Link>;
|
||||
};
|
||||
|
||||
// ── Sidebar card ──
|
||||
|
||||
interface SidebarCardProps {
|
||||
readonly title: string;
|
||||
readonly count?: number;
|
||||
readonly isLoading?: boolean;
|
||||
readonly action?: { label: string; href: string };
|
||||
readonly children: React.ReactNode;
|
||||
}
|
||||
|
||||
const SidebarCard = ({ title, count, isLoading, action, children }: SidebarCardProps) => (
|
||||
<Box
|
||||
border={ CARD_BORDER }
|
||||
borderColor="border.divider"
|
||||
borderRadius="lg"
|
||||
p={ 4 }
|
||||
bgColor={ CARD_BG }
|
||||
>
|
||||
<Flex align="center" justify="space-between" mb={ 3 }>
|
||||
<Flex align="center" gap={ 2 }>
|
||||
<Heading level="3" fontSize="sm">{ title }</Heading>
|
||||
{ count !== undefined && (
|
||||
<Skeleton loading={ isLoading }>
|
||||
<Tag size="sm" variant="subtle">{ count }</Tag>
|
||||
</Skeleton>
|
||||
) }
|
||||
</Flex>
|
||||
{ action && (
|
||||
<Link href={ action.href } textStyle="xs" color="text.secondary" _hover={{ color: 'text.primary' }}>
|
||||
{ action.label }
|
||||
</Link>
|
||||
) }
|
||||
</Flex>
|
||||
{ children }
|
||||
</Box>
|
||||
);
|
||||
|
||||
// ── Main page ──
|
||||
|
||||
const NetworkOverview = () => {
|
||||
const isMobile = useIsMobile();
|
||||
const { stats, isLoading: validatorsLoading } = useCurrentValidators();
|
||||
@@ -169,110 +211,175 @@ const NetworkOverview = () => {
|
||||
|
||||
return (
|
||||
<Box as="main">
|
||||
{ /* ── Hero search ── */ }
|
||||
<HeroBanner/>
|
||||
|
||||
{ /* ── Metrics strip ── */ }
|
||||
<Flex
|
||||
justify="space-around"
|
||||
justify="center"
|
||||
align="center"
|
||||
py={ 4 }
|
||||
px={{ base: 4, lg: 6 }}
|
||||
py={ 3 }
|
||||
mt={ 4 }
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
border={ CARD_BORDER }
|
||||
borderColor="border.divider"
|
||||
bgColor={ STAT_CARD_BG }
|
||||
gap={ 4 }
|
||||
bgColor={ CARD_BG }
|
||||
gap={ 0 }
|
||||
flexWrap="wrap"
|
||||
overflow="hidden"
|
||||
>
|
||||
<NetworkStat label="Total Chains" value={ String(totalChains) } isLoading={ isLoading }/>
|
||||
<Box w="1px" h="32px" bgColor="border.divider" display={{ base: 'none', lg: 'block' }}/>
|
||||
<NetworkStat label="Validators" value={ String(stats.validatorCount) } isLoading={ isLoading }/>
|
||||
<Box w="1px" h="32px" bgColor="border.divider" display={{ base: 'none', lg: 'block' }}/>
|
||||
<NetworkStat
|
||||
label="Total Stake"
|
||||
value={ `${ formatStake(stats.totalStake) } LUX` }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<Box w="1px" h="32px" bgColor="border.divider" display={{ base: 'none', lg: 'block' }}/>
|
||||
<NetworkStat
|
||||
label="Avg Uptime"
|
||||
value={ `${ stats.averageUptime.toFixed(1) }%` }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<Box w="1px" h="32px" bgColor="border.divider" display={{ base: 'none', lg: 'block' }}/>
|
||||
<NetworkStat
|
||||
label="Connected"
|
||||
value={ `${ stats.connectedCount }/${ stats.validatorCount }` }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
<Metric label="Chains" value={ String(totalChains) } isLoading={ isLoading }/>
|
||||
<Box w="1px" h="28px" bgColor="border.divider" display={{ base: 'none', md: 'block' }}/>
|
||||
<Metric label="Validators" value={ String(stats.validatorCount) } isLoading={ isLoading }/>
|
||||
<Box w="1px" h="28px" bgColor="border.divider" display={{ base: 'none', md: 'block' }}/>
|
||||
<Metric label="Staked" value={ `${ formatStake(stats.totalStake) } LUX` } isLoading={ isLoading }/>
|
||||
<Box w="1px" h="28px" bgColor="border.divider" display={{ base: 'none', md: 'block' }}/>
|
||||
<Metric label="Uptime" value={ `${ stats.averageUptime.toFixed(1) }%` } isLoading={ isLoading }/>
|
||||
<Box w="1px" h="28px" bgColor="border.divider" display={{ base: 'none', md: 'block' }}/>
|
||||
<Metric label="Connected" value={ `${ stats.connectedCount }/${ stats.validatorCount }` } isLoading={ isLoading }/>
|
||||
</Flex>
|
||||
|
||||
<Flex mt={ 6 } gap={ 6 } flexDir={{ base: 'column', lg: 'row' }}>
|
||||
<Stats/>
|
||||
<LatestBlocks/>
|
||||
</Flex>
|
||||
|
||||
<Box mt={ 6 }>
|
||||
<Transactions/>
|
||||
</Box>
|
||||
|
||||
{ /* ── Two-column: Activity (primary) + Chain Health (secondary) ── */ }
|
||||
<Grid
|
||||
templateColumns={{ base: '1fr', lg: '1fr 1fr' }}
|
||||
gap={{ base: 6, lg: 8 }}
|
||||
mt={ 8 }
|
||||
templateColumns={{ base: '1fr', lg: '1fr 340px' }}
|
||||
gap={ 5 }
|
||||
mt={ 5 }
|
||||
>
|
||||
{ /* ── Left: Activity ── */ }
|
||||
<Box>
|
||||
<Flex align="center" justify="space-between" mb={ 3 }>
|
||||
<Heading level="3">Primary Network</Heading>
|
||||
<Tag size="sm" variant="subtle">{ PRIMARY_CHAINS.length }</Tag>
|
||||
</Flex>
|
||||
<Flex direction="column" gap={ 2 }>
|
||||
{ PRIMARY_CHAINS.map((chain) => (
|
||||
<ChainCard
|
||||
key={ chain.id }
|
||||
name={ chain.name }
|
||||
fullName={ chain.fullName }
|
||||
vm={ chain.vm }
|
||||
href={ chain.href }
|
||||
/>
|
||||
)) }
|
||||
</Flex>
|
||||
{ /* Stats grid */ }
|
||||
<Stats/>
|
||||
|
||||
{ /* Latest blocks */ }
|
||||
<Box mt={ 5 }>
|
||||
<LatestBlocks/>
|
||||
</Box>
|
||||
|
||||
{ /* Transactions */ }
|
||||
<Box mt={ 5 }>
|
||||
<Transactions/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Flex align="center" justify="space-between" mb={ 3 }>
|
||||
<Heading level="3">L1 Chains</Heading>
|
||||
<Skeleton loading={ chainsLoading }>
|
||||
<Tag size="sm" variant="subtle">{ l1Chains.length }</Tag>
|
||||
</Skeleton>
|
||||
</Flex>
|
||||
{ chainsLoading && (
|
||||
<Flex direction="column" gap={ 2 }>
|
||||
{ Array.from({ length: 4 }).map((_, i) => (
|
||||
<Skeleton key={ i } loading h="68px" borderRadius="md"/>
|
||||
{ /* ── Right: Chain Health sidebar ── */ }
|
||||
<Flex direction="column" gap={ 4 } display={{ base: 'none', lg: 'flex' }}>
|
||||
{ /* Primary Network chains */ }
|
||||
<SidebarCard
|
||||
title="Primary Network"
|
||||
count={ PRIMARY_CHAINS.length }
|
||||
>
|
||||
<Flex direction="column" gap={ 0 }>
|
||||
{ PRIMARY_CHAINS.map((chain) => (
|
||||
<ChainRow
|
||||
key={ chain.id }
|
||||
name={ chain.name }
|
||||
fullName={ chain.fullName }
|
||||
vm={ chain.vm }
|
||||
href={ chain.href }
|
||||
/>
|
||||
)) }
|
||||
</Flex>
|
||||
) }
|
||||
{ !chainsLoading && l1Chains.length === 0 && (
|
||||
<Text color="text.secondary" fontSize="sm" py={ 4 }>
|
||||
No L1 chains registered yet.
|
||||
</Text>
|
||||
) }
|
||||
{ !chainsLoading && l1Chains.length > 0 && (
|
||||
<Flex direction="column" gap={ 2 }>
|
||||
{ l1Chains.map((chain) => (
|
||||
<L1ChainCard key={ chain.id } chain={ chain }/>
|
||||
)) }
|
||||
</Flex>
|
||||
) }
|
||||
</SidebarCard>
|
||||
|
||||
{ !isMobile && (
|
||||
<Flex justify="center" mt={ 4 }>
|
||||
<Link href="/chains" textStyle="sm">View all chains</Link>
|
||||
{ /* Subnet / L1 chains — renamed to just "Chains" */ }
|
||||
<SidebarCard
|
||||
title="Chains"
|
||||
count={ l1Chains.length }
|
||||
isLoading={ chainsLoading }
|
||||
action={{ label: 'View all', href: '/chains' }}
|
||||
>
|
||||
{ chainsLoading && (
|
||||
<Flex direction="column" gap={ 1 }>
|
||||
{ Array.from({ length: 4 }).map((_, i) => (
|
||||
<Skeleton key={ i } loading h="40px" borderRadius="md"/>
|
||||
)) }
|
||||
</Flex>
|
||||
) }
|
||||
{ !chainsLoading && l1Chains.length === 0 && (
|
||||
<Text color="text.secondary" fontSize="sm" py={ 2 }>
|
||||
No chains registered yet.
|
||||
</Text>
|
||||
) }
|
||||
{ !chainsLoading && l1Chains.length > 0 && (
|
||||
<Flex direction="column" gap={ 0 }>
|
||||
{ l1Chains.map((chain) => (
|
||||
<L1ChainRow key={ chain.id } chain={ chain }/>
|
||||
)) }
|
||||
</Flex>
|
||||
) }
|
||||
</SidebarCard>
|
||||
|
||||
{ /* Validators summary card */ }
|
||||
<SidebarCard title="Validators">
|
||||
<Grid templateColumns="1fr 1fr" gap={ 3 }>
|
||||
<Box>
|
||||
<Skeleton loading={ isLoading }>
|
||||
<Text fontWeight={ 700 } fontFamily="mono" fontSize="md">
|
||||
{ stats.validatorCount }
|
||||
</Text>
|
||||
</Skeleton>
|
||||
<Text fontSize="2xs" color="text.secondary">Active</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Skeleton loading={ isLoading }>
|
||||
<Text fontWeight={ 700 } fontFamily="mono" fontSize="md">
|
||||
{ formatStake(stats.totalStake) }
|
||||
</Text>
|
||||
</Skeleton>
|
||||
<Text fontSize="2xs" color="text.secondary">Total Stake (LUX)</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Skeleton loading={ isLoading }>
|
||||
<Text fontWeight={ 700 } fontFamily="mono" fontSize="md">
|
||||
{ stats.delegatorCount }
|
||||
</Text>
|
||||
</Skeleton>
|
||||
<Text fontSize="2xs" color="text.secondary">Delegators</Text>
|
||||
</Box>
|
||||
<Box>
|
||||
<Skeleton loading={ isLoading }>
|
||||
<Text fontWeight={ 700 } fontFamily="mono" fontSize="md">
|
||||
{ `${ stats.connectedCount }/${ stats.validatorCount }` }
|
||||
</Text>
|
||||
</Skeleton>
|
||||
<Text fontSize="2xs" color="text.secondary">Connected</Text>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Flex justify="center" mt={ 3 }>
|
||||
<Link href="/validators" textStyle="xs" color="text.secondary" _hover={{ color: 'text.primary' }}>
|
||||
View validators
|
||||
</Link>
|
||||
</Flex>
|
||||
) }
|
||||
</Box>
|
||||
</SidebarCard>
|
||||
</Flex>
|
||||
</Grid>
|
||||
|
||||
{ /* ── Mobile-only chains section ── */ }
|
||||
{ isMobile && (
|
||||
<Box mt={ 5 }>
|
||||
<SidebarCard
|
||||
title="Chains"
|
||||
count={ totalChains }
|
||||
isLoading={ isLoading }
|
||||
action={{ label: 'View all', href: '/chains' }}
|
||||
>
|
||||
<Flex direction="column" gap={ 0 }>
|
||||
{ PRIMARY_CHAINS.slice(0, 5).map((chain) => (
|
||||
<ChainRow
|
||||
key={ chain.id }
|
||||
name={ chain.name }
|
||||
fullName={ chain.fullName }
|
||||
vm={ chain.vm }
|
||||
href={ chain.href }
|
||||
/>
|
||||
)) }
|
||||
{ l1Chains.map((chain) => (
|
||||
<L1ChainRow key={ chain.id } chain={ chain }/>
|
||||
)) }
|
||||
</Flex>
|
||||
</SidebarCard>
|
||||
</Box>
|
||||
) }
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ export default function RewardsActivityPassCard() {
|
||||
<Link external href={ activityPassUrl } loading={ rewardsConfigQuery.isLoading }>
|
||||
Activity pass
|
||||
</Link>{ ' ' }
|
||||
then engage with various Blockscout products and features to earn Merits every day!{ ' ' }
|
||||
then engage with various Lux Explorer products and features to earn Merits every day!{ ' ' }
|
||||
<Link external href="https://docs.blockscout.com/using-blockscout/merits/activity-pass">
|
||||
Learn more
|
||||
</Link>
|
||||
|
||||
@@ -111,10 +111,10 @@ export default function ActivityTab() {
|
||||
const tasks = useMemo(() => (
|
||||
[
|
||||
{
|
||||
title: 'Blockscout activity',
|
||||
title: 'Lux Explorer activity',
|
||||
description: (
|
||||
<>
|
||||
Use Blockscout tools like{ ' ' }
|
||||
Use Lux Explorer tools like{ ' ' }
|
||||
<Link
|
||||
external={ !marketplaceFeature?.essentialDapps }
|
||||
href={ marketplaceFeature?.essentialDapps ?
|
||||
@@ -144,7 +144,7 @@ export default function ActivityTab() {
|
||||
<Link href={ route({ pathname: '/contract-verification' }) }>
|
||||
verify a smart contract
|
||||
</Link>{ ' ' }
|
||||
on the Blockscout explorer to earn Merits.
|
||||
on the Lux Explorer to earn Merits.
|
||||
</>
|
||||
),
|
||||
percentile: activities.contracts?.percentile,
|
||||
@@ -154,11 +154,11 @@ export default function ActivityTab() {
|
||||
maxAmount: getMaxAmount(rewardsConfigQuery.data?.rewards?.verified_contracts_activity_rewards),
|
||||
},
|
||||
{
|
||||
title: 'Blockscout usage',
|
||||
title: 'Lux Explorer usage',
|
||||
description: (
|
||||
<>
|
||||
Use Blockscout explorers in your daily routine { mdash } check transactions, explore addresses,
|
||||
or add tokens/networks to MetaMask via Blockscout.
|
||||
Use Lux Explorer in your daily routine { mdash } check transactions, explore addresses,
|
||||
or add tokens/networks to MetaMask via Lux Explorer.
|
||||
</>
|
||||
),
|
||||
percentile: activities.usage?.percentile,
|
||||
@@ -220,7 +220,7 @@ export default function ActivityTab() {
|
||||
<Flex flexDirection="column" p={{ base: 1.5, md: 0 }} pb={ 0 }>
|
||||
<Heading level="3" mb={ 2 }>Your activity</Heading>
|
||||
<Text textStyle="sm" mb={{ base: 2, md: 4 }}>
|
||||
Use Blockscout and related products daily to earn Merits. Check each task for details and how to get started.
|
||||
Use Lux Explorer and related products daily to earn Merits. Check each task for details and how to get started.
|
||||
</Text>
|
||||
<Flex alignItems="center" gap={ 3 } mb={{ base: 0, md: 4 }}>
|
||||
<Button
|
||||
|
||||
@@ -121,9 +121,9 @@ const LoginStepContent = ({ goNext, closeModal, openAuthModal }: Props) => {
|
||||
fallback={ <Skeleton loading w="full" h="120px"/> }
|
||||
/>
|
||||
<Box mb={ 6 }>
|
||||
Merits are awarded for a variety of different Blockscout activities. Connect a wallet to get started.
|
||||
Merits are awarded for a variety of different Lux Explorer activities. Connect a wallet to get started.
|
||||
<Link external href="https://docs.blockscout.com/using-blockscout/merits" ml={ 1 } fontWeight="500">
|
||||
More about Blockscout Merits
|
||||
More about Lux Explorer Merits
|
||||
</Link>
|
||||
</Box>
|
||||
{ isSignUp && isLoggedIntoAccountWithWallet && (
|
||||
@@ -159,7 +159,7 @@ const LoginStepContent = ({ goNext, closeModal, openAuthModal }: Props) => {
|
||||
) }
|
||||
{ isAddressMismatch && (
|
||||
<Alert status="warning" mb={ 4 }>
|
||||
Your wallet address doesn{ apos }t match the one in your Blockscout account. Please connect the correct wallet.
|
||||
Your wallet address doesn{ apos }t match the one in your Lux Explorer account. Please connect the correct wallet.
|
||||
</Alert>
|
||||
) }
|
||||
<Button
|
||||
@@ -175,7 +175,7 @@ const LoginStepContent = ({ goNext, closeModal, openAuthModal }: Props) => {
|
||||
{ buttonText }
|
||||
</Button>
|
||||
<Text textStyle="sm" color="text.secondary" textAlign="center">
|
||||
Already registered for Blockscout Merits on another network or chain? Connect the same wallet here.
|
||||
Already registered for Lux Explorer Merits on another network or chain? Connect the same wallet here.
|
||||
</Text>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -43,11 +43,11 @@ const AuthModalScreenSuccessEmail = ({ email, onConnectWallet, onClose, isAuth,
|
||||
<Box>
|
||||
<Text>
|
||||
<chakra.span fontWeight="700">{ email }</chakra.span>{ ' ' }
|
||||
email has been successfully used to log in to your Blockscout account.
|
||||
email has been successfully used to log in to your Lux account.
|
||||
</Text>
|
||||
{ !profile?.address_hash && config.features.blockchainInteraction.isEnabled ? (
|
||||
<>
|
||||
<Text mt={ 6 }>Add your web3 wallet to safely interact with smart contracts and dapps inside Blockscout.</Text>
|
||||
<Text mt={ 6 }>Add your web3 wallet to safely interact with smart contracts and dapps inside Lux Explorer.</Text>
|
||||
<Button mt={ 6 } onClick={ handleConnectWalletClick }>Connect wallet</Button>
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -47,13 +47,13 @@ const AuthModalScreenSuccessWallet = ({ address, onAddEmail, onClose, isAuth, pr
|
||||
<Text>
|
||||
Wallet{ ' ' }
|
||||
<chakra.span fontWeight="700">{ shortenString(address) }</chakra.span>{ ' ' }
|
||||
has been successfully used to log in to your Blockscout account
|
||||
has been successfully used to log in to your Lux account
|
||||
{ Boolean(rewardsToken) && ` and Merits Program` }.
|
||||
</Text>
|
||||
{ !profile?.email ? (
|
||||
<>
|
||||
<Text mt={ 6 }>
|
||||
Add your email to receive exclusive updates about Blockscout { config.features.rewards.isEnabled ? 'Merits ' : ' ' }
|
||||
Add your email to receive exclusive updates about Lux Explorer { config.features.rewards.isEnabled ? 'Merits ' : ' ' }
|
||||
and notifications about addresses in your watch list.
|
||||
</Text>
|
||||
<Flex mt={ 6 } gap={ 6 }>
|
||||
|
||||
@@ -129,16 +129,13 @@ const Footer = () => {
|
||||
|
||||
return (
|
||||
<Box gridArea={ gridArea }>
|
||||
<Flex columnGap={ 2 } textStyle="xs" alignItems="center">
|
||||
<span>Powered by</span>
|
||||
<Link href="https://lux.network" external noIcon display="inline-flex" color={ logoColor } _hover={{ color: logoColor }}>
|
||||
<IconSvg
|
||||
name="networks/logo-placeholder"
|
||||
width="80px"
|
||||
height={ 4 }
|
||||
/>
|
||||
</Link>
|
||||
</Flex>
|
||||
<Link href="https://lux.network" external noIcon display="inline-flex" color={ logoColor } _hover={{ color: logoColor }}>
|
||||
<IconSvg
|
||||
name="networks/logo-placeholder"
|
||||
width="80px"
|
||||
height={ 4 }
|
||||
/>
|
||||
</Link>
|
||||
<Text mt={ 3 } fontSize="xs">
|
||||
Lux Network is a high-performance blockchain platform for decentralized applications and custom blockchain networks.
|
||||
</Text>
|
||||
@@ -154,7 +151,7 @@ const Footer = () => {
|
||||
</Text>
|
||||
) }
|
||||
<Text>
|
||||
Copyright { copy } Lux Network 2023-{ (new Date()).getFullYear() }
|
||||
{ copy } { (new Date()).getFullYear() } Lux Industries Inc. All rights reserved.
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -6,8 +6,8 @@ export default function getApiVersionUrl(version: string | undefined): string |
|
||||
const [ tag, commit ] = version.split('.+commit.');
|
||||
|
||||
if (commit) {
|
||||
return `https://github.com/blockscout/blockscout/commit/${ commit }`;
|
||||
return `https://github.com/luxfi/explorer/commit/${ commit }`;
|
||||
}
|
||||
|
||||
return `https://github.com/blockscout/blockscout/tree/${ tag }`;
|
||||
return `https://github.com/luxfi/explorer/tree/${ tag }`;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { getCurrentChain } from 'configs/app/chainRegistry';
|
||||
import { Link } from 'toolkit/chakra/link';
|
||||
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from 'toolkit/chakra/menu';
|
||||
import { CONTENT_MAX_WIDTH } from 'ui/shared/layout/utils';
|
||||
import UserProfileDesktop from 'ui/snippets/user/UserProfileDesktop';
|
||||
import SearchBar from 'ui/snippets/searchBar/SearchBarDesktop';
|
||||
|
||||
import ChainSwitcher from './ChainSwitcher';
|
||||
import NetworkSelector from './NetworkSelector';
|
||||
@@ -83,48 +83,47 @@ const TopBar = () => {
|
||||
maxW={ `${ CONTENT_MAX_WIDTH }px` }
|
||||
gap={ 1 }
|
||||
>
|
||||
{ /* ── Logo + Network brand ── */ }
|
||||
<chakra.a
|
||||
href={ route({ pathname: '/' as const }) }
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
gap="6px"
|
||||
flexShrink={ 0 }
|
||||
mr={ 3 }
|
||||
aria-label={ `${ chain.branding.brandName } home` }
|
||||
textDecoration="none"
|
||||
_hover={{ textDecoration: 'none', opacity: 0.8 }}
|
||||
transition="opacity 0.15s"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox={ chain.branding.logoViewBox }
|
||||
width="18"
|
||||
height="18"
|
||||
dangerouslySetInnerHTML={{ __html: chain.branding.logoContent }}
|
||||
/>
|
||||
<chakra.span
|
||||
fontWeight={ 700 }
|
||||
fontSize="sm"
|
||||
letterSpacing="-0.02em"
|
||||
whiteSpace="nowrap"
|
||||
color="text.primary"
|
||||
{ /* ── Logo + Brand + Chain/Network selectors (grouped) ── */ }
|
||||
<Flex alignItems="center" gap={ 1.5 } flexShrink={ 0 }>
|
||||
<chakra.a
|
||||
href={ route({ pathname: '/' as const }) }
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
gap="6px"
|
||||
flexShrink={ 0 }
|
||||
aria-label={ `${ chain.branding.brandName } home` }
|
||||
textDecoration="none"
|
||||
_hover={{ textDecoration: 'none', opacity: 0.8 }}
|
||||
transition="opacity 0.15s"
|
||||
>
|
||||
{ chain.branding.brandName }
|
||||
</chakra.span>
|
||||
</chakra.a>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox={ chain.branding.logoViewBox }
|
||||
width="18"
|
||||
height="18"
|
||||
dangerouslySetInnerHTML={{ __html: chain.branding.logoContent }}
|
||||
/>
|
||||
<chakra.span
|
||||
fontWeight={ 700 }
|
||||
fontSize="sm"
|
||||
letterSpacing="-0.02em"
|
||||
whiteSpace="nowrap"
|
||||
color="text.primary"
|
||||
>
|
||||
{ chain.branding.brandName }
|
||||
</chakra.span>
|
||||
</chakra.a>
|
||||
|
||||
{ /* Chain & Network selectors — directly next to brand name */ }
|
||||
<NetworkSelector/>
|
||||
<ChainSwitcher/>
|
||||
</Flex>
|
||||
|
||||
{ /* ── Divider ── */ }
|
||||
<Box h="16px" w="1px" bgColor="border.divider" flexShrink={ 0 } mr={ 2 }/>
|
||||
<Box h="16px" w="1px" bgColor="border.divider" flexShrink={ 0 } mx={ 1 }/>
|
||||
|
||||
{ /* ── Navigation ── */ }
|
||||
{ /* ── Navigation (no Home — logo click does that) ── */ }
|
||||
<HStack as="nav" gap={ 0 } display={{ base: 'none', lg: 'flex' }} flexShrink={ 0 }>
|
||||
<NavLinkItem
|
||||
text="Home"
|
||||
href={ route({ pathname: '/' as const }) }
|
||||
isActive={ pathname === '/' }
|
||||
/>
|
||||
|
||||
{ /* Blockchain dropdown */ }
|
||||
<MenuRoot>
|
||||
<MenuTrigger asChild>
|
||||
@@ -206,15 +205,13 @@ const TopBar = () => {
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
{ /* ── Spacer ── */ }
|
||||
<Box flex={ 1 }/>
|
||||
{ /* ── Search bar (center, flexible) ── */ }
|
||||
<Box flex={ 1 } mx={ 2 } display={{ base: 'none', lg: 'block' }} maxW="480px">
|
||||
<SearchBar isHeroBanner={ false }/>
|
||||
</Box>
|
||||
|
||||
{ /* ── Right controls ── */ }
|
||||
<HStack gap={ 1.5 } flexShrink={ 0 }>
|
||||
<NetworkSelector/>
|
||||
<ChainSwitcher/>
|
||||
<UserProfileDesktop buttonSize="sm"/>
|
||||
</HStack>
|
||||
{ /* ── Spacer ── */ }
|
||||
<Box flex={ 1 } display={{ base: 'block', lg: 'none' }}/>
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -96,7 +96,7 @@ const UserProfileContent = ({ data, onClose, onLogin, onAddEmail, onAddAddress }
|
||||
<Flex p={ 2 } borderColor="border.divider" borderBottomWidth="1px">
|
||||
<Box>Address</Box>
|
||||
<Hint
|
||||
label={ `This wallet address is linked to your Blockscout account. It can be used to login ${ config.features.rewards.isEnabled ? 'and is used for Merits Program participation' : '' }` } // eslint-disable-line max-len
|
||||
label={ `This wallet address is linked to your Lux account. It can be used to login ${ config.features.rewards.isEnabled ? 'and is used for Merits Program participation' : '' }` } // eslint-disable-line max-len
|
||||
boxSize={ 4 }
|
||||
ml={ 1 }
|
||||
/>
|
||||
|
||||
@@ -92,7 +92,7 @@ const UserProfileContentWallet = ({ onClose, className }: Props) => {
|
||||
<Hint
|
||||
label={
|
||||
web3Wallet.isConnected ?
|
||||
'This wallet is currently connected to Blockscout and used for interacting with apps and smart contracts' :
|
||||
'This wallet is currently connected to Lux Explorer and used for interacting with apps and smart contracts' :
|
||||
'This wallet is used for interacting with apps and smart contracts'
|
||||
}
|
||||
boxSize={ 4 }
|
||||
|
||||
Reference in New Issue
Block a user