Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
30193c74
Commit
30193c74
authored
Sep 30, 2022
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rewrite network menu
parent
73bb6ce1
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
168 additions
and
48 deletions
+168
-48
.env.template
.env.template
+10
-0
config.ts
configs/app/config.ts
+14
-0
link.ts
lib/link/link.ts
+7
-9
routes.ts
lib/link/routes.ts
+0
-7
featuredNetworks.ts
lib/networks/featuredNetworks.ts
+110
-0
parseNetworkConfig.js
lib/networks/parseNetworkConfig.js
+2
-2
useNetworkNavigationItems.ts
lib/networks/useNetworkNavigationItems.ts
+8
-20
middleware.ts
middleware.ts
+2
-3
networks.ts
types/networks.ts
+8
-0
NetworkMenuContentDesktop.tsx
ui/snippets/networkMenu/NetworkMenuContentDesktop.tsx
+1
-1
NetworkMenuContentMobile.tsx
ui/snippets/networkMenu/NetworkMenuContentMobile.tsx
+1
-1
NetworkMenuLink.tsx
ui/snippets/networkMenu/NetworkMenuLink.tsx
+5
-5
No files found.
.env.template
View file @
30193c74
...
...
@@ -6,3 +6,13 @@ NEXT_PUBLIC_FOOTER_TELEGRAM_LINK=APP_NEXT_NEXT_PUBLIC_FOOTER_TELEGRAM_LINK
NEXT_PUBLIC_FOOTER_STAKING_LINK=APP_NEXT_NEXT_PUBLIC_FOOTER_STAKING_LINK
NEXT_PUBLIC_SENTRY_DSN=APP_NEXT_NEXT_PUBLIC_SENTRY_DSN
NEXT_PUBLIC_APP_INSTANCE=APP_NEXT_NEXT_PUBLIC_APP_INSTANCE
NEXT_PUBLIC_NETWORK_NAME=APP_NEXT_NEXT_PUBLIC_NETWORK_NAME
NEXT_PUBLIC_NETWORK_SHORT_NAME=APP_NEXT_NEXT_PUBLIC_NETWORK_SHORT_NAME
NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=APP_NEXT_NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME
NEXT_PUBLIC_NETWORK_TYPE=APP_NEXT_NEXT_PUBLIC_NETWORK_TYPE
NEXT_PUBLIC_NETWORK_SUBTYPE=APP_NEXT_NEXT_PUBLIC_NETWORK_SUBTYPE
NEXT_PUBLIC_NETWORK_ID=APP_NEXT_NEXT_PUBLIC_NETWORK_ID
NEXT_PUBLIC_NETWORK_CURRENCY=APP_NEXT_NEXT_PUBLIC_NETWORK_CURRENCY
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=APP_NEXT_NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=APP_NEXT_NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED
NEXT_PUBLIC_FEATURED_NETWORKS=APP_NEXT_NEXT_PUBLIC_FEATURED_NETWORKS
configs/app/config.ts
0 → 100644
View file @
30193c74
const
env
=
process
.
env
.
VERCEL_ENV
||
process
.
env
.
NODE_ENV
;
const
isDev
=
env
===
'
development
'
;
const
config
=
Object
.
freeze
({
env
,
isDev
,
networkType
:
process
.
env
.
NEXT_PUBLIC_NETWORK_TYPE
,
networkSubtype
:
process
.
env
.
NEXT_PUBLIC_NETWORK_SUBTYPE
,
basePath
:
'
/
'
+
[
process
.
env
.
NEXT_PUBLIC_NETWORK_TYPE
,
process
.
env
.
NEXT_PUBLIC_NETWORK_SUBTYPE
].
filter
(
Boolean
).
join
(
'
/
'
),
// TODO domain should be passed in CI during runtime
domain
:
isDev
?
'
http://localhost:3000
'
:
'
https://blockscout.com
'
,
});
export
default
config
;
lib/link/link.ts
View file @
30193c74
import
isBrowser
from
'
lib/isBrowser
'
;
import
findNetwork
from
'
lib/networks/findNetwork
'
;
import
appConfig
from
'
configs/app/config
'
;
import
{
ROUTES
}
from
'
./routes
'
;
import
type
{
RouteName
}
from
'
./routes
'
;
...
...
@@ -12,27 +11,26 @@ export function link(routeName: RouteName, urlParams?: Record<string, Array<stri
return
''
;
}
const
network
=
findNetwork
({
network_type
:
typeof
urlParams
?.
network_type
===
'
string
'
?
urlParams
?.
network_type
:
''
,
network_sub_type
:
typeof
urlParams
?.
network_sub_type
===
'
string
'
?
urlParams
?.
network_sub_type
:
undefined
,
});
// if we pass network type, we have to get subtype from params too
// otherwise getting it from config since it is not cross-chain link
const
networkSubType
=
typeof
urlParams
?.
network_type
===
'
string
'
?
urlParams
?.
network_sub_type
:
appConfig
.
networkSubtype
;
const
path
=
route
.
pattern
.
replace
(
PATH_PARAM_REGEXP
,
(
_
,
paramName
:
string
)
=>
{
if
(
paramName
===
'
network_sub_type
'
&&
!
network
?.
s
ubType
)
{
if
(
paramName
===
'
network_sub_type
'
&&
!
network
S
ubType
)
{
return
''
;
}
let
paramValue
=
urlParams
?.[
paramName
];
if
(
Array
.
isArray
(
paramValue
))
{
// FIXME we don't have yet params as array, but typescript says that we could
// dun
't
know how to manage it, fix me if you find an issue
// dun
no
know how to manage it, fix me if you find an issue
paramValue
=
paramValue
.
join
(
'
,
'
);
}
return
paramValue
?
`/
${
paramValue
}
`
:
''
;
});
const
url
=
new
URL
(
path
,
isBrowser
()
?
window
.
location
.
origin
:
'
https://blockscout.com
'
);
const
url
=
new
URL
(
path
,
appConfig
.
domain
);
queryParams
&&
Object
.
entries
(
queryParams
).
forEach
(([
key
,
value
])
=>
{
url
.
searchParams
.
append
(
key
,
value
);
...
...
lib/link/routes.ts
View file @
30193c74
...
...
@@ -17,31 +17,24 @@ export const ROUTES = {
// ACCOUNT
watchlist
:
{
pattern
:
`
${
BASE_PATH
}
/account/watchlist`
,
crossNetworkNavigation
:
true
,
},
private_tags_address
:
{
pattern
:
`
${
BASE_PATH
}
/account/tag_address`
,
crossNetworkNavigation
:
true
,
},
private_tags_tx
:
{
pattern
:
`
${
BASE_PATH
}
/account/tag_transaction`
,
crossNetworkNavigation
:
true
,
},
public_tags
:
{
pattern
:
`
${
BASE_PATH
}
/account/public_tags_request`
,
crossNetworkNavigation
:
true
,
},
api_keys
:
{
pattern
:
`
${
BASE_PATH
}
/account/api_key`
,
crossNetworkNavigation
:
true
,
},
custom_abi
:
{
pattern
:
`
${
BASE_PATH
}
/account/custom_abi`
,
crossNetworkNavigation
:
true
,
},
profile
:
{
pattern
:
`
${
BASE_PATH
}
/auth/profile`
,
crossNetworkNavigation
:
true
,
},
// TRANSACTIONS
...
...
lib/networks/featuredNetworks.ts
0 → 100644
View file @
30193c74
import
type
{
FeaturedNetwork
}
from
'
types/networks
'
;
import
arbitrumIcon
from
'
icons/networks/icons/arbitrum.svg
'
;
import
artisIcon
from
'
icons/networks/icons/artis.svg
'
;
import
ethereumClassicIcon
from
'
icons/networks/icons/ethereum-classic.svg
'
;
import
ethereumIcon
from
'
icons/networks/icons/ethereum.svg
'
;
import
gnosisIcon
from
'
icons/networks/icons/gnosis.svg
'
;
import
optimismIcon
from
'
icons/networks/icons/optimism.svg
'
;
import
poaSokolIcon
from
'
icons/networks/icons/poa-sokol.svg
'
;
import
poaIcon
from
'
icons/networks/icons/poa.svg
'
;
import
rskIcon
from
'
icons/networks/icons/rsk.svg
'
;
// predefined network icons
const
ICONS
:
Record
<
string
,
React
.
FunctionComponent
<
React
.
SVGAttributes
<
SVGElement
>>>
=
{
'
/xdai/mainnet
'
:
gnosisIcon
,
'
/xdai/optimism
'
:
optimismIcon
,
'
/xdai/aox
'
:
arbitrumIcon
,
'
/eth/mainnet
'
:
ethereumIcon
,
'
/etc/mainnet
'
:
ethereumClassicIcon
,
'
/poa/core
'
:
poaIcon
,
'
/rsk/mainnet
'
:
rskIcon
,
'
/xdai/testnet
'
:
arbitrumIcon
,
'
/poa/sokol
'
:
poaSokolIcon
,
'
/artis/sigma1
'
:
artisIcon
,
};
// for easy .env.example update
// const FEATURED_NETWORKS = JSON.stringify([
// {
// title: 'Gnosis Chain',
// basePath: '/xdai/mainnet',
// group: 'mainnets',
// },
// {
// title: 'Optimism on Gnosis Chain',
// basePath: '/xdai/optimism',
// group: 'mainnets',
// icon: 'https://www.fillmurray.com/60/60',
// },
// {
// title: 'Arbitrum on xDai',
// basePath: '/xdai/aox',
// group: 'mainnets',
// },
// {
// title: 'Ethereum',
// basePath: '/eth/mainnet',
// group: 'mainnets',
// },
// {
// title: 'Ethereum Classic',
// basePath: '/etx/mainnet',
// group: 'mainnets',
// },
// {
// title: 'POA',
// basePath: '/poa/core',
// group: 'mainnets',
// },
// {
// title: 'RSK',
// basePath: '/rsk/mainnet',
// group: 'mainnets',
// },
// {
// title: 'Gnosis Chain Testnet',
// basePath: '/xdai/testnet',
// group: 'testnets',
// },
// {
// title: 'POA Sokol',
// basePath: '/poa/sokol',
// group: 'testnets',
// },
// {
// title: 'ARTIS Σ1',
// basePath: '/artis/sigma1',
// group: 'other',
// },
// {
// title: 'LUKSO L14',
// basePath: '/lukso/l14',
// group: 'other',
// },
// {
// title: 'Astar',
// basePath: '/astar',
// group: 'other',
// },
// ]);
const
CONFIG_VALUE
=
process
.
env
.
NEXT_PUBLIC_FEATURED_NETWORKS
?.
replaceAll
(
'
\'
'
,
'
"
'
);
function
parseNetworkConfig
()
{
try
{
return
JSON
.
parse
(
CONFIG_VALUE
||
'
[]
'
);
}
catch
(
error
)
{
return
[];
}
}
const
featuredNetworks
:
Array
<
FeaturedNetwork
>
=
(()
=>
{
const
networksFromConfig
:
Array
<
FeaturedNetwork
>
=
parseNetworkConfig
();
return
networksFromConfig
.
map
((
network
)
=>
({
...
network
,
icon
:
network
.
icon
||
ICONS
[
network
.
basePath
],
}));
})();
export
default
featuredNetworks
;
lib/networks/parseNetworkConfig.js
View file @
30193c74
const
supportedNetworks
=
process
.
env
.
NEXT_PUBLIC_SUPPORT
ED_NETWORKS
?.
replaceAll
(
'
\'
'
,
'
"
'
);
const
featuredNetworks
=
process
.
env
.
NEXT_PUBLIC_FEATUR
ED_NETWORKS
?.
replaceAll
(
'
\'
'
,
'
"
'
);
// should be CommonJS module since it used for next.config.js
function
parseNetworkConfig
()
{
try
{
return
JSON
.
parse
(
support
edNetworks
||
'
[]
'
);
return
JSON
.
parse
(
featur
edNetworks
||
'
[]
'
);
}
catch
(
error
)
{
return
[];
}
...
...
lib/networks/useNetworkNavigationItems.ts
View file @
30193c74
import
appConfig
from
'
configs/app/config
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
useNetwork
from
'
lib/hooks/useNetwork
'
;
import
isAccountRoute
from
'
lib/link/isAccountRoute
'
;
import
{
link
}
from
'
lib/link/link
'
;
import
{
ROUTES
}
from
'
lib/link/routes
'
;
import
useCurrentRoute
from
'
lib/link/useCurrentRoute
'
;
import
NETWORKS
from
'
lib/networks/available
Networks
'
;
import
featuredNetworks
from
'
lib/networks/featured
Networks
'
;
export
default
function
useNetworkNavigationItems
()
{
const
selectedNetwork
=
useNetwork
();
const
currentRouteName
=
useCurrentRoute
()();
const
currentRoute
=
ROUTES
[
currentRouteName
];
const
router
=
useRouter
();
const
isAccount
=
isAccountRoute
(
currentRouteName
);
return
React
.
useMemo
(()
=>
{
return
NETWORKS
.
map
((
network
)
=>
{
const
routeName
=
(()
=>
{
if
(
'
crossNetworkNavigation
'
in
currentRoute
&&
currentRoute
.
crossNetworkNavigation
)
{
if
((
isAccount
&&
network
.
isAccountSupported
)
||
!
isAccount
)
{
return
currentRouteName
;
}
}
return
'
network_index
'
;
})();
const
url
=
link
(
routeName
,
{
...
router
.
query
,
network_type
:
network
.
type
,
network_sub_type
:
network
.
subType
});
return
featuredNetworks
.
map
((
network
)
=>
{
const
routeName
=
'
crossNetworkNavigation
'
in
currentRoute
&&
currentRoute
.
crossNetworkNavigation
?
currentRouteName
:
'
network_index
'
;
const
[
,
networkType
,
networkSubtype
]
=
network
.
basePath
.
split
(
'
/
'
);
const
url
=
link
(
routeName
,
{
...
router
.
query
,
network_type
:
networkType
,
network_sub_type
:
networkSubtype
});
return
{
...
network
,
url
:
url
,
isActive
:
selectedNetwork
?.
type
===
network
.
type
&&
selectedNetwork
?.
subType
===
network
?.
subType
,
isActive
:
appConfig
.
basePath
===
network
.
basePath
,
};
});
},
[
currentRoute
,
currentRouteName
,
isAccount
,
router
.
query
,
selectedNetwork
?.
subType
,
selectedNetwork
?.
type
]);
},
[
currentRoute
,
currentRouteName
,
router
.
query
]);
}
middleware.ts
View file @
30193c74
import
appConfig
from
'
configs/app/config
'
;
import
type
{
NextRequest
}
from
'
next/server
'
;
import
{
NextResponse
}
from
'
next/server
'
;
import
{
NAMES
}
from
'
lib/cookies
'
;
import
getCspPolicy
from
'
lib/csp/getCspPolicy
'
;
import
{
link
}
from
'
lib/link/link
'
;
import
findNetwork
from
'
lib/networks/findNetwork
'
;
const
cspPolicy
=
getCspPolicy
();
...
...
@@ -20,9 +20,8 @@ export function middleware(req: NextRequest) {
network_type
:
networkType
,
network_sub_type
:
networkSubtype
,
};
const
selectedNetwork
=
findNetwork
(
networkParams
);
if
(
!
selectedNetwork
)
{
if
(
appConfig
.
networkType
!==
networkType
&&
appConfig
.
networkSubtype
!==
networkSubtype
)
{
const
url
=
req
.
nextUrl
.
clone
();
url
.
pathname
=
`/404`
;
return
NextResponse
.
rewrite
(
url
);
...
...
types/networks.ts
View file @
30193c74
...
...
@@ -2,6 +2,7 @@ import type { FunctionComponent, SVGAttributes } from 'react';
export
type
NetworkGroup
=
'
mainnets
'
|
'
testnets
'
|
'
other
'
;
// todo_tom delete this
export
interface
Network
{
name
:
string
;
chainId
:
number
;
// https://chainlist.org/
...
...
@@ -17,3 +18,10 @@ export interface Network {
isAccountSupported
?:
boolean
;
assetsNamePath
?:
string
;
}
export
interface
FeaturedNetwork
{
title
:
string
;
basePath
:
string
;
group
:
'
mainnets
'
|
'
testnets
'
|
'
other
'
;
icon
?:
FunctionComponent
<
SVGAttributes
<
SVGElement
>>
|
string
;
}
ui/snippets/networkMenu/NetworkMenuContentDesktop.tsx
View file @
30193c74
...
...
@@ -35,7 +35,7 @@ const NetworkMenuPopup = () => {
.
filter
((
network
)
=>
network
.
group
===
tab
)
.
map
((
network
)
=>
(
<
NetworkMenuLink
key=
{
network
.
nam
e
}
key=
{
network
.
titl
e
}
{
...
network
}
/>
))
}
...
...
ui/snippets/networkMenu/NetworkMenuContentMobile.tsx
View file @
30193c74
...
...
@@ -30,7 +30,7 @@ const NetworkMenuContentMobile = () => {
.
filter
(({
group
})
=>
group
===
selectedTab
)
.
map
((
network
)
=>
(
<
NetworkMenuLink
key=
{
network
.
nam
e
}
key=
{
network
.
titl
e
}
{
...
network
}
isMobile
/>
...
...
ui/snippets/networkMenu/NetworkMenuLink.tsx
View file @
30193c74
...
...
@@ -2,25 +2,25 @@ import { Box, Flex, Icon, Text, Image } from '@chakra-ui/react';
import
NextLink
from
'
next/link
'
;
import
React
from
'
react
'
;
import
type
{
Network
}
from
'
types/networks
'
;
import
type
{
Featured
Network
}
from
'
types/networks
'
;
import
checkIcon
from
'
icons/check.svg
'
;
import
placeholderIcon
from
'
icons/networks/icons/placeholder.svg
'
;
import
useColors
from
'
./useColors
'
;
interface
Props
extends
Network
{
interface
Props
extends
Featured
Network
{
isActive
:
boolean
;
isMobile
?:
boolean
;
url
:
string
;
}
const
NetworkMenuLink
=
({
name
,
type
,
subTyp
e
,
icon
,
isActive
,
isMobile
,
url
}:
Props
)
=>
{
const
NetworkMenuLink
=
({
titl
e
,
icon
,
isActive
,
isMobile
,
url
}:
Props
)
=>
{
const
hasIcon
=
Boolean
(
icon
);
const
colors
=
useColors
({
hasIcon
});
const
iconEl
=
typeof
icon
===
'
string
'
?
(
<
Image
w=
"30px"
h=
"30px"
src=
{
icon
}
alt=
{
`${ t
ype } ${ subType ? subType : ''
} network icon`
}
/>
<
Image
w=
"30px"
h=
"30px"
src=
{
icon
}
alt=
{
`${ t
itle
} network icon`
}
/>
)
:
(
<
Icon
as=
{
hasIcon
?
icon
:
placeholderIcon
}
...
...
@@ -52,7 +52,7 @@ const NetworkMenuLink = ({ name, type, subType, icon, isActive, isMobile, url }:
fontSize=
{
isMobile
?
'
sm
'
:
'
md
'
}
lineHeight=
{
isMobile
?
'
20px
'
:
'
24px
'
}
>
{
nam
e
}
{
titl
e
}
</
Text
>
{
isActive
&&
(
<
Icon
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment