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
a51725d0
Commit
a51725d0
authored
Feb 12, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
validators and coin balance tabs
parent
8600aeba
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
325 additions
and
261 deletions
+325
-261
semanticTokens.ts
toolkit/theme/foundations/semanticTokens.ts
+6
-0
address-entity.ts
toolkit/theme/globals/address-entity.ts
+1
-0
index.ts
toolkit/theme/recipes/index.ts
+2
-0
menu.recipe.ts
toolkit/theme/recipes/menu.recipe.ts
+1
-1
stat.recipe.ts
toolkit/theme/recipes/stat.recipe.ts
+101
-0
AddressBlocksValidated.tsx
ui/address/AddressBlocksValidated.tsx
+23
-22
AddressTxs.tsx
ui/address/AddressTxs.tsx
+1
-1
AddressBlocksValidatedListItem.tsx
...ddress/blocksValidated/AddressBlocksValidatedListItem.tsx
+12
-12
AddressBlocksValidatedTableItem.tsx
...dress/blocksValidated/AddressBlocksValidatedTableItem.tsx
+21
-21
AddressCoinBalanceChart.tsx
ui/address/coinBalance/AddressCoinBalanceChart.tsx
+1
-1
AddressCoinBalanceHistory.tsx
ui/address/coinBalance/AddressCoinBalanceHistory.tsx
+23
-22
AddressCoinBalanceListItem.tsx
ui/address/coinBalance/AddressCoinBalanceListItem.tsx
+14
-16
AddressCoinBalanceTableItem.tsx
ui/address/coinBalance/AddressCoinBalanceTableItem.tsx
+24
-27
Address.tsx
ui/pages/Address.tsx
+15
-15
ChartAxis.tsx
ui/shared/chart/ChartAxis.tsx
+5
-4
ChartMenu.tsx
ui/shared/chart/ChartMenu.tsx
+30
-49
ChartWatermarkIcon.tsx
ui/shared/chart/ChartWatermarkIcon.tsx
+2
-3
ChartWidget.tsx
ui/shared/chart/ChartWidget.tsx
+14
-22
ChartWidgetContent.tsx
ui/shared/chart/ChartWidgetContent.tsx
+6
-5
ChartWidgetGraph.tsx
ui/shared/chart/ChartWidgetGraph.tsx
+1
-1
FullscreenChartModal.tsx
ui/shared/chart/FullscreenChartModal.tsx
+21
-38
TxsTableItem.tsx
ui/txs/TxsTableItem.tsx
+1
-1
No files found.
toolkit/theme/foundations/semanticTokens.ts
View file @
a51725d0
...
...
@@ -353,6 +353,12 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
},
},
},
stat
:
{
indicator
:
{
up
:
{
value
:
{
_light
:
'
{colors.green.500}
'
,
_dark
:
'
{colors.green.400}
'
}
},
down
:
{
value
:
{
_light
:
'
{colors.red.600}
'
,
_dark
:
'
{colors.red.400}
'
}
},
},
},
heading
:
{
DEFAULT
:
{
value
:
{
_light
:
'
{colors.blackAlpha.800}
'
,
_dark
:
'
{colors.whiteAlpha.800}
'
}
},
},
...
...
toolkit/theme/globals/address-entity.ts
View file @
a51725d0
...
...
@@ -24,6 +24,7 @@ const styles = {
'
&.address-entity_highlighted
'
:
{
_before
:
{
pr
:
2
,
width
:
`calc(100% + 6px + 8px)`
,
},
},
},
...
...
toolkit/theme/recipes/index.ts
View file @
a51725d0
...
...
@@ -20,6 +20,7 @@ import { recipe as radiomark } from './radiomark.recipe';
import
{
recipe
as
select
}
from
'
./select.recipe
'
;
import
{
recipe
as
skeleton
}
from
'
./skeleton.recipe
'
;
import
{
recipe
as
spinner
}
from
'
./spinner.recipe
'
;
import
{
recipe
as
stat
}
from
'
./stat.recipe
'
;
import
{
recipe
as
switchRecipe
}
from
'
./switch.recipe
'
;
import
{
recipe
as
table
}
from
'
./table.recipe
'
;
import
{
recipe
as
tabs
}
from
'
./tabs.recipe
'
;
...
...
@@ -55,6 +56,7 @@ export const slotRecipes = {
progressCircle
,
radioGroup
,
select
,
stat
,
'
switch
'
:
switchRecipe
,
table
,
tabs
,
...
...
toolkit/theme/recipes/menu.recipe.ts
View file @
a51725d0
...
...
@@ -5,7 +5,7 @@ export const recipe = defineSlotRecipe({
base
:
{
content
:
{
outline
:
0
,
bg
:
'
popover
,
bg
'
,
bg
:
'
popover
.
bg
'
,
boxShadow
:
'
popover
'
,
color
:
'
initial
'
,
maxHeight
:
'
var(--available-height)
'
,
...
...
toolkit/theme/recipes/stat.recipe.ts
0 → 100644
View file @
a51725d0
import
{
defineSlotRecipe
}
from
'
@chakra-ui/react
'
;
export
const
recipe
=
defineSlotRecipe
({
slots
:
[
'
root
'
,
'
label
'
,
'
helpText
'
,
'
valueUnit
'
,
'
valueText
'
,
'
indicator
'
],
base
:
{
root
:
{
display
:
'
flex
'
,
flexDirection
:
'
column
'
,
gap
:
'
1
'
,
position
:
'
relative
'
,
flex
:
'
1
'
,
},
label
:
{
display
:
'
inline-flex
'
,
gap
:
'
1.5
'
,
alignItems
:
'
center
'
,
color
:
'
text
'
,
textStyle
:
'
sm
'
,
},
helpText
:
{
color
:
'
text
'
,
textStyle
:
'
xs
'
,
},
valueUnit
:
{
color
:
'
text
'
,
textStyle
:
'
xs
'
,
fontWeight
:
'
initial
'
,
letterSpacing
:
'
initial
'
,
},
valueText
:
{
verticalAlign
:
'
baseline
'
,
fontWeight
:
'
semibold
'
,
letterSpacing
:
'
normal
'
,
fontFeatureSettings
:
'
initial
'
,
fontVariantNumeric
:
'
initial
'
,
display
:
'
inline-flex
'
,
gap
:
'
1
'
,
},
indicator
:
{
display
:
'
inline-flex
'
,
alignItems
:
'
center
'
,
justifyContent
:
'
center
'
,
marginEnd
:
0
,
'
& :where(svg)
'
:
{
w
:
'
1em
'
,
h
:
'
1em
'
,
},
'
&[data-type=up]
'
:
{
color
:
'
stat.indicator.up
'
,
},
'
&[data-type=down]
'
:
{
color
:
'
stat.indicator.down
'
,
},
},
},
variants
:
{
orientation
:
{
horizontal
:
{
root
:
{
flexDirection
:
'
row
'
,
alignItems
:
'
center
'
,
},
},
},
positive
:
{
'
true
'
:
{
valueText
:
{
color
:
'
stat.indicator.up
'
,
},
},
'
false
'
:
{
valueText
:
{
color
:
'
stat.indicator.down
'
,
},
},
},
size
:
{
sm
:
{
valueText
:
{
textStyle
:
'
sm
'
,
},
},
md
:
{
valueText
:
{
textStyle
:
'
md
'
,
},
},
lg
:
{
valueText
:
{
textStyle
:
'
lg
'
,
},
},
},
},
defaultVariants
:
{
size
:
'
md
'
,
orientation
:
'
horizontal
'
,
},
});
ui/address/AddressBlocksValidated.tsx
View file @
a51725d0
import
{
Hide
,
Show
,
Table
,
Tbody
,
Th
,
Tr
}
from
'
@chakra-ui/react
'
;
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
{
useQueryClient
}
from
'
@tanstack/react-query
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
...
...
@@ -14,12 +14,12 @@ import useSocketMessage from 'lib/socket/useSocketMessage';
import
{
currencyUnits
}
from
'
lib/units
'
;
import
{
BLOCK
}
from
'
stubs/block
'
;
import
{
generateListStub
}
from
'
stubs/utils
'
;
import
{
TableBody
,
TableColumnHeader
,
TableHeaderSticky
,
TableRoot
,
TableRow
}
from
'
toolkit/chakra/table
'
;
import
ActionBar
,
{
ACTION_BAR_HEIGHT_DESKTOP
}
from
'
ui/shared/ActionBar
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
useQueryWithPages
from
'
ui/shared/pagination/useQueryWithPages
'
;
import
*
as
SocketNewItemsNotice
from
'
ui/shared/SocketNewItemsNotice
'
;
import
{
default
as
Thead
}
from
'
ui/shared/TheadSticky
'
;
import
AddressBlocksValidatedListItem
from
'
./blocksValidated/AddressBlocksValidatedListItem
'
;
import
AddressBlocksValidatedTableItem
from
'
./blocksValidated/AddressBlocksValidatedTableItem
'
;
...
...
@@ -104,19 +104,19 @@ const AddressBlocksValidated = ({ scrollRef, shouldRender = true, isQueryEnabled
const
content
=
query
.
data
?.
items
?
(
<>
<
Hide
below=
"lg"
ssr=
{
false
}
>
<
Table
style=
{
{
tableLayout
:
'
auto
'
}
}
>
<
T
head
top=
{
query
.
pagination
.
isVisible
?
ACTION_BAR_HEIGHT_DESKTOP
:
0
}
>
<
T
r
>
<
T
h
>
Block
</
Th
>
<
T
h
>
Age
</
Th
>
<
T
h
>
Txn
</
Th
>
<
T
h
>
Gas used
</
Th
>
<
Box
hideBelow=
"lg"
>
<
Table
Root
style=
{
{
tableLayout
:
'
auto
'
}
}
>
<
T
ableHeaderSticky
top=
{
query
.
pagination
.
isVisible
?
ACTION_BAR_HEIGHT_DESKTOP
:
0
}
>
<
T
ableRow
>
<
T
ableColumnHeader
>
Block
</
TableColumnHeader
>
<
T
ableColumnHeader
>
Age
</
TableColumnHeader
>
<
T
ableColumnHeader
>
Txn
</
TableColumnHeader
>
<
T
ableColumnHeader
>
Gas used
</
TableColumnHeader
>
{
!
config
.
UI
.
views
.
block
.
hiddenFields
?.
total_reward
&&
!
config
.
features
.
rollup
.
isEnabled
&&
<
Th
isNumeric
>
Reward
{
currencyUnits
.
ether
}
</
Th
>
}
</
T
r
>
</
T
head
>
<
T
b
ody
>
<
TableColumnHeader
isNumeric
>
Reward
{
currencyUnits
.
ether
}
</
TableColumnHeader
>
}
</
T
ableRow
>
</
T
ableHeaderSticky
>
<
T
ableB
ody
>
<
SocketNewItemsNotice
.
Desktop
url=
{
window
.
location
.
href
}
num=
{
newItemsCount
}
...
...
@@ -132,10 +132,10 @@ const AddressBlocksValidated = ({ scrollRef, shouldRender = true, isQueryEnabled
isLoading=
{
query
.
isPlaceholderData
}
/>
))
}
</
T
b
ody
>
</
Table
>
</
Hide
>
<
Show
below=
"lg"
ssr=
{
false
}
>
</
T
ableB
ody
>
</
Table
Root
>
</
Box
>
<
Box
hideFrom=
"lg"
>
{
query
.
pagination
.
page
===
1
&&
(
<
SocketNewItemsNotice
.
Mobile
url=
{
window
.
location
.
href
}
...
...
@@ -153,7 +153,7 @@ const AddressBlocksValidated = ({ scrollRef, shouldRender = true, isQueryEnabled
isLoading=
{
query
.
isPlaceholderData
}
/>
))
}
</
Show
>
</
Box
>
</>
)
:
null
;
...
...
@@ -166,11 +166,12 @@ const AddressBlocksValidated = ({ scrollRef, shouldRender = true, isQueryEnabled
return
(
<
DataListDisplay
isError=
{
query
.
isError
}
items
=
{
query
.
data
?.
items
}
items
Num=
{
query
.
data
?.
items
.
length
}
emptyText=
"There are no validated blocks for this address."
content=
{
content
}
actionBar=
{
actionBar
}
/>
>
{
content
}
</
DataListDisplay
>
);
};
...
...
ui/address/AddressTxs.tsx
View file @
a51725d0
...
...
@@ -187,7 +187,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT, shouldRender =
return (
<>
{ !isMobile && (
<ActionBar
mt={ -6 }
>
<ActionBar>
{ filter }
{ currentAddress && csvExportLink }
<Pagination { ...addressTxsQuery.pagination } ml={ 8 }/>
...
...
ui/address/blocksValidated/AddressBlocksValidatedListItem.tsx
View file @
a51725d0
...
...
@@ -7,8 +7,8 @@ import type { Block } from 'types/api/block';
import
config
from
'
configs/app
'
;
import
getBlockTotalReward
from
'
lib/block/getBlockTotalReward
'
;
import
{
currencyUnits
}
from
'
lib/units
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
BlockGasUsed
from
'
ui/shared/block/BlockGasUsed
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
import
TimeAgoWithTooltip
from
'
ui/shared/TimeAgoWithTooltip
'
;
...
...
@@ -22,7 +22,7 @@ const AddressBlocksValidatedListItem = (props: Props) => {
const
totalReward
=
getBlockTotalReward
(
props
);
return
(
<
ListItemMobile
rowGap=
{
2
}
isAnimated
>
<
ListItemMobile
rowGap=
{
2
}
>
<
Flex
justifyContent=
"space-between"
w=
"100%"
>
<
BlockEntity
isLoading=
{
props
.
isLoading
}
...
...
@@ -34,32 +34,32 @@ const AddressBlocksValidatedListItem = (props: Props) => {
timestamp=
{
props
.
timestamp
}
enableIncrement=
{
props
.
page
===
1
}
isLoading=
{
props
.
isLoading
}
color=
"text
_
secondary"
color=
"text
.
secondary"
display=
"inline-block"
/>
</
Flex
>
<
Flex
columnGap=
{
2
}
w=
"100%"
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Txn
</
Skeleton
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
display=
"inline-block"
color=
"Skeleton_secondary"
>
<
Skeleton
loading=
{
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Txn
</
Skeleton
>
<
Skeleton
loading=
{
props
.
isLoading
}
display=
"inline-block"
color=
"Skeleton_secondary"
>
<
span
>
{
props
.
transaction_count
}
</
span
>
</
Skeleton
>
</
Flex
>
<
Flex
columnGap=
{
2
}
w=
"100%"
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Gas used
</
Skeleton
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
>
<
Text
color=
"text
_
secondary"
>
{
BigNumber
(
props
.
gas_used
||
0
).
toFormat
()
}
</
Text
>
<
Skeleton
loading=
{
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Gas used
</
Skeleton
>
<
Skeleton
loading=
{
props
.
isLoading
}
>
<
Text
color=
"text
.
secondary"
>
{
BigNumber
(
props
.
gas_used
||
0
).
toFormat
()
}
</
Text
>
</
Skeleton
>
<
BlockGasUsed
gasUsed=
{
props
.
gas_used
}
gasUsed=
{
props
.
gas_used
||
undefined
}
gasLimit=
{
props
.
gas_limit
}
isLoading=
{
props
.
isLoading
}
/>
</
Flex
>
{
!
config
.
UI
.
views
.
block
.
hiddenFields
?.
total_reward
&&
!
config
.
features
.
rollup
.
isEnabled
&&
(
<
Flex
columnGap=
{
2
}
w=
"100%"
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Reward
{
currencyUnits
.
ether
}
</
Skeleton
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
>
<
Text
color=
"text
_
secondary"
>
{
totalReward
.
toFixed
()
}
</
Text
>
<
Skeleton
loading=
{
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Reward
{
currencyUnits
.
ether
}
</
Skeleton
>
<
Skeleton
loading=
{
props
.
isLoading
}
>
<
Text
color=
"text
.
secondary"
>
{
totalReward
.
toFixed
()
}
</
Text
>
</
Skeleton
>
</
Flex
>
)
}
...
...
ui/address/blocksValidated/AddressBlocksValidatedTableItem.tsx
View file @
a51725d0
import
{
Td
,
Tr
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
Flex
}
from
'
@chakra-ui/react
'
;
import
BigNumber
from
'
bignumber.js
'
;
import
React
from
'
react
'
;
...
...
@@ -6,8 +6,9 @@ import type { Block } from 'types/api/block';
import
config
from
'
configs/app
'
;
import
getBlockTotalReward
from
'
lib/block/getBlockTotalReward
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
TableCell
,
TableRow
}
from
'
toolkit/chakra/table
'
;
import
BlockGasUsed
from
'
ui/shared/block/BlockGasUsed
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
TimeAgoWithTooltip
from
'
ui/shared/TimeAgoWithTooltip
'
;
...
...
@@ -20,51 +21,50 @@ const AddressBlocksValidatedTableItem = (props: Props) => {
const
totalReward
=
getBlockTotalReward
(
props
);
return
(
<
T
r
>
<
T
d
>
<
T
ableRow
>
<
T
ableCell
>
<
BlockEntity
isLoading=
{
props
.
isLoading
}
number=
{
props
.
height
}
noIcon
fontSize=
"sm"
lineHeight=
{
5
}
textStyle=
"sm"
fontWeight=
{
700
}
/>
</
T
d
>
<
T
d
>
</
T
ableCell
>
<
T
ableCell
>
<
TimeAgoWithTooltip
timestamp=
{
props
.
timestamp
}
enableIncrement=
{
props
.
page
===
1
}
isLoading=
{
props
.
isLoading
}
color=
"text
_
secondary"
color=
"text
.
secondary"
display=
"inline-block"
/>
</
T
d
>
<
T
d
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
display=
"inline-block"
fontWeight=
"500"
>
</
T
ableCell
>
<
T
ableCell
>
<
Skeleton
loading=
{
props
.
isLoading
}
display=
"inline-block"
fontWeight=
"500"
>
<
span
>
{
props
.
transaction_count
}
</
span
>
</
Skeleton
>
</
T
d
>
<
T
d
>
</
T
ableCell
>
<
T
ableCell
>
<
Flex
alignItems=
"center"
columnGap=
{
2
}
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
flexBasis=
"80px"
>
<
Skeleton
loading=
{
props
.
isLoading
}
flexBasis=
"80px"
>
{
BigNumber
(
props
.
gas_used
||
0
).
toFormat
()
}
</
Skeleton
>
<
BlockGasUsed
gasUsed=
{
props
.
gas_used
}
gasUsed=
{
props
.
gas_used
||
undefined
}
gasLimit=
{
props
.
gas_limit
}
isLoading=
{
props
.
isLoading
}
/>
</
Flex
>
</
T
d
>
</
T
ableCell
>
{
!
config
.
UI
.
views
.
block
.
hiddenFields
?.
total_reward
&&
!
config
.
features
.
rollup
.
isEnabled
&&
(
<
T
d
isNumeric
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
display=
"inline-block"
>
<
T
ableCell
isNumeric
>
<
Skeleton
loading=
{
props
.
isLoading
}
display=
"inline-block"
>
<
span
>
{
totalReward
.
toFixed
()
}
</
span
>
</
Skeleton
>
</
T
d
>
</
T
ableCell
>
)
}
</
T
r
>
</
T
ableRow
>
);
};
...
...
ui/address/coinBalance/AddressCoinBalanceChart.tsx
View file @
a51725d0
...
...
@@ -34,7 +34,7 @@ const AddressCoinBalanceChart = ({ addressHash }: Props) => {
isLoading=
{
isPending
}
h=
"300px"
units=
{
currencyUnits
.
ether
}
emptyText=
{
data
?.
days
&&
`Insufficient data for the past ${ data.days } days`
}
emptyText=
{
data
?.
days
?
`Insufficient data for the past ${ data.days } days`
:
undefined
}
/>
);
};
...
...
ui/address/coinBalance/AddressCoinBalanceHistory.tsx
View file @
a51725d0
import
{
Hide
,
Show
,
Table
,
Tbody
,
Th
,
Tr
}
from
'
@chakra-ui/react
'
;
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
type
{
UseQueryResult
}
from
'
@tanstack/react-query
'
;
import
React
from
'
react
'
;
...
...
@@ -7,10 +7,10 @@ import type { PaginationParams } from 'ui/shared/pagination/types';
import
type
{
ResourceError
}
from
'
lib/api/resources
'
;
import
{
currencyUnits
}
from
'
lib/units
'
;
import
{
TableBody
,
TableColumnHeader
,
TableHeaderSticky
,
TableRoot
,
TableRow
}
from
'
toolkit/chakra/table
'
;
import
ActionBar
,
{
ACTION_BAR_HEIGHT_DESKTOP
}
from
'
ui/shared/ActionBar
'
;
import
DataListDisplay
from
'
ui/shared/DataListDisplay
'
;
import
Pagination
from
'
ui/shared/pagination/Pagination
'
;
import
{
default
as
Thead
}
from
'
ui/shared/TheadSticky
'
;
import
AddressCoinBalanceListItem
from
'
./AddressCoinBalanceListItem
'
;
import
AddressCoinBalanceTableItem
from
'
./AddressCoinBalanceTableItem
'
;
...
...
@@ -25,18 +25,18 @@ const AddressCoinBalanceHistory = ({ query }: Props) => {
const
content
=
query
.
data
?.
items
?
(
<>
<
Hide
below=
"lg"
ssr=
{
false
}
>
<
Table
>
<
T
head
top=
{
query
.
pagination
.
isVisible
?
ACTION_BAR_HEIGHT_DESKTOP
:
0
}
>
<
T
r
>
<
T
h
width=
"20%"
>
Block
</
Th
>
<
T
h
width=
"20%"
>
Txn
</
Th
>
<
T
h
width=
"20%"
>
Age
</
Th
>
<
T
h
width=
"20%"
isNumeric
pr=
{
1
}
>
Balance
{
currencyUnits
.
ether
}
</
Th
>
<
T
h
width=
"20%"
isNumeric
>
Delta
</
Th
>
</
T
r
>
</
T
head
>
<
T
b
ody
>
<
Box
hideBelow=
"lg"
>
<
Table
Root
>
<
T
ableHeaderSticky
top=
{
query
.
pagination
.
isVisible
?
ACTION_BAR_HEIGHT_DESKTOP
:
0
}
>
<
T
ableRow
>
<
T
ableColumnHeader
width=
"20%"
>
Block
</
TableColumnHeader
>
<
T
ableColumnHeader
width=
"20%"
>
Txn
</
TableColumnHeader
>
<
T
ableColumnHeader
width=
"20%"
>
Age
</
TableColumnHeader
>
<
T
ableColumnHeader
width=
"20%"
isNumeric
pr=
{
1
}
>
Balance
{
currencyUnits
.
ether
}
</
TableColumnHeader
>
<
T
ableColumnHeader
width=
"20%"
isNumeric
>
Delta
</
TableColumnHeader
>
</
T
ableRow
>
</
T
ableHeaderSticky
>
<
T
ableB
ody
>
{
query
.
data
.
items
.
map
((
item
,
index
)
=>
(
<
AddressCoinBalanceTableItem
key=
{
item
.
block_number
+
(
query
.
isPlaceholderData
?
String
(
index
)
:
''
)
}
...
...
@@ -45,10 +45,10 @@ const AddressCoinBalanceHistory = ({ query }: Props) => {
isLoading=
{
query
.
isPlaceholderData
}
/>
))
}
</
T
b
ody
>
</
Table
>
</
Hide
>
<
Show
below=
"lg"
ssr=
{
false
}
>
</
T
ableB
ody
>
</
Table
Root
>
</
Box
>
<
Box
hideFrom=
"lg"
>
{
query
.
data
.
items
.
map
((
item
,
index
)
=>
(
<
AddressCoinBalanceListItem
key=
{
item
.
block_number
+
(
query
.
isPlaceholderData
?
String
(
index
)
:
''
)
}
...
...
@@ -57,7 +57,7 @@ const AddressCoinBalanceHistory = ({ query }: Props) => {
isLoading=
{
query
.
isPlaceholderData
}
/>
))
}
</
Show
>
</
Box
>
</>
)
:
null
;
...
...
@@ -71,11 +71,12 @@ const AddressCoinBalanceHistory = ({ query }: Props) => {
<
DataListDisplay
mt=
{
8
}
isError=
{
query
.
isError
}
items
=
{
query
.
data
?.
items
}
items
Num=
{
query
.
data
?.
items
.
length
}
emptyText=
"There is no coin balance history for this address."
content=
{
content
}
actionBar=
{
actionBar
}
/>
>
{
content
}
</
DataListDisplay
>
);
};
...
...
ui/address/coinBalance/AddressCoinBalanceListItem.tsx
View file @
a51725d0
import
{
Text
,
Stat
,
StatHelpText
,
StatArrow
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
Stat
,
Flex
}
from
'
@chakra-ui/react
'
;
import
BigNumber
from
'
bignumber.js
'
;
import
React
from
'
react
'
;
...
...
@@ -6,7 +6,7 @@ import type { AddressCoinBalanceHistoryItem } from 'types/api/address';
import
{
WEI
,
ZERO
}
from
'
lib/consts
'
;
import
{
currencyUnits
}
from
'
lib/units
'
;
import
Skeleton
from
'
ui/shared/chakra/S
keleton
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/s
keleton
'
;
import
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
TxEntity
from
'
ui/shared/entities/tx/TxEntity
'
;
import
ListItemMobile
from
'
ui/shared/ListItemMobile/ListItemMobile
'
;
...
...
@@ -22,24 +22,22 @@ const AddressCoinBalanceListItem = (props: Props) => {
const
isPositiveDelta
=
deltaBn
.
gte
(
ZERO
);
return
(
<
ListItemMobile
rowGap=
{
2
}
isAnimated
>
<
ListItemMobile
rowGap=
{
2
}
>
<
Flex
justifyContent=
"space-between"
w=
"100%"
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
fontWeight=
{
600
}
>
<
Skeleton
loading=
{
props
.
isLoading
}
fontWeight=
{
600
}
>
{
BigNumber
(
props
.
value
).
div
(
WEI
).
dp
(
8
).
toFormat
()
}
{
currencyUnits
.
ether
}
</
Skeleton
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
>
<
Stat
flexGrow=
"0"
>
<
StatHelpText
display=
"flex"
mb=
{
0
}
alignItems=
"center"
>
<
StatArrow
type=
{
isPositiveDelta
?
'
increase
'
:
'
decrease
'
}
mr=
{
2
}
/>
<
Text
as=
"span"
color=
{
isPositiveDelta
?
'
green.500
'
:
'
red.500
'
}
fontWeight=
{
600
}
>
{
deltaBn
.
dp
(
8
).
toFormat
()
}
</
Text
>
</
StatHelpText
>
</
Stat
>
<
Skeleton
loading=
{
props
.
isLoading
}
>
<
Stat
.
Root
flexGrow=
"0"
positive=
{
isPositiveDelta
}
size=
"sm"
>
{
isPositiveDelta
?
<
Stat
.
UpIndicator
/>
:
<
Stat
.
DownIndicator
/>
}
<
Stat
.
ValueText
fontWeight=
{
600
}
>
{
deltaBn
.
dp
(
8
).
toFormat
()
}
</
Stat
.
ValueText
>
</
Stat
.
Root
>
</
Skeleton
>
</
Flex
>
<
Flex
columnGap=
{
2
}
w=
"100%"
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Block
</
Skeleton
>
<
Skeleton
loading=
{
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Block
</
Skeleton
>
<
BlockEntity
isLoading=
{
props
.
isLoading
}
number=
{
props
.
block_number
}
...
...
@@ -49,7 +47,7 @@ const AddressCoinBalanceListItem = (props: Props) => {
</
Flex
>
{
props
.
transaction_hash
&&
(
<
Flex
columnGap=
{
2
}
w=
"100%"
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Txs
</
Skeleton
>
<
Skeleton
loading=
{
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Txs
</
Skeleton
>
<
TxEntity
hash=
{
props
.
transaction_hash
}
isLoading=
{
props
.
isLoading
}
...
...
@@ -60,7 +58,7 @@ const AddressCoinBalanceListItem = (props: Props) => {
</
Flex
>
)
}
<
Flex
columnGap=
{
2
}
w=
"100%"
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Age
</
Skeleton
>
<
Skeleton
loading=
{
props
.
isLoading
}
fontWeight=
{
500
}
flexShrink=
{
0
}
>
Age
</
Skeleton
>
<
TimeAgoWithTooltip
timestamp=
{
props
.
block_timestamp
}
enableIncrement=
{
props
.
page
===
1
}
...
...
ui/address/coinBalance/AddressCoinBalanceTableItem.tsx
View file @
a51725d0
import
{
Td
,
Tr
,
Text
,
Stat
,
StatHelpText
,
StatArrow
}
from
'
@chakra-ui/react
'
;
import
{
Stat
}
from
'
@chakra-ui/react
'
;
import
BigNumber
from
'
bignumber.js
'
;
import
React
from
'
react
'
;
import
type
{
AddressCoinBalanceHistoryItem
}
from
'
types/api/address
'
;
import
{
WEI
,
ZERO
}
from
'
lib/consts
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
TableCell
,
TableRow
}
from
'
toolkit/chakra/table
'
;
import
BlockEntity
from
'
ui/shared/entities/block/BlockEntity
'
;
import
TxEntity
from
'
ui/shared/entities/tx/TxEntity
'
;
import
TimeAgoWithTooltip
from
'
ui/shared/TimeAgoWithTooltip
'
;
...
...
@@ -20,18 +21,16 @@ const AddressCoinBalanceTableItem = (props: Props) => {
const
isPositiveDelta
=
deltaBn
.
gte
(
ZERO
);
return
(
<
T
r
>
<
T
d
>
<
T
ableRow
>
<
T
ableCell
>
<
BlockEntity
isLoading=
{
props
.
isLoading
}
number=
{
props
.
block_number
}
noIcon
fontSize=
"sm"
lineHeight=
{
5
}
fontWeight=
{
700
}
/>
</
T
d
>
<
T
d
>
</
T
ableCell
>
<
T
ableCell
>
{
props
.
transaction_hash
&&
(
<
TxEntity
hash=
{
props
.
transaction_hash
}
...
...
@@ -41,34 +40,32 @@ const AddressCoinBalanceTableItem = (props: Props) => {
maxW=
"150px"
/>
)
}
</
T
d
>
<
T
d
>
</
T
ableCell
>
<
T
ableCell
>
<
TimeAgoWithTooltip
timestamp=
{
props
.
block_timestamp
}
enableIncrement=
{
props
.
page
===
1
}
isLoading=
{
props
.
isLoading
}
color=
"text
_
secondary"
color=
"text
.
secondary"
display=
"inline-block"
/>
</
T
d
>
<
T
d
isNumeric
pr=
{
1
}
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
color=
"text_
secondary"
display=
"inline-block"
>
</
T
ableCell
>
<
T
ableCell
isNumeric
pr=
{
1
}
>
<
Skeleton
loading=
{
props
.
isLoading
}
color=
"text.
secondary"
display=
"inline-block"
>
<
span
>
{
BigNumber
(
props
.
value
).
div
(
WEI
).
dp
(
8
).
toFormat
()
}
</
span
>
</
Skeleton
>
</
Td
>
<
Td
isNumeric
display=
"flex"
justifyContent=
"end"
>
<
Skeleton
isLoaded=
{
!
props
.
isLoading
}
>
<
Stat
flexGrow=
"0"
lineHeight=
{
5
}
>
<
StatHelpText
display=
"flex"
mb=
{
0
}
alignItems=
"center"
>
<
StatArrow
type=
{
isPositiveDelta
?
'
increase
'
:
'
decrease
'
}
mr=
{
2
}
/>
<
Text
as=
"span"
color=
{
isPositiveDelta
?
'
green.500
'
:
'
red.500
'
}
fontWeight=
{
600
}
>
{
deltaBn
.
dp
(
8
).
toFormat
()
}
</
Text
>
</
StatHelpText
>
</
Stat
>
</
TableCell
>
<
TableCell
isNumeric
display=
"flex"
justifyContent=
"end"
>
<
Skeleton
loading=
{
props
.
isLoading
}
>
<
Stat
.
Root
flexGrow=
"0"
size=
"sm"
positive=
{
isPositiveDelta
}
>
{
isPositiveDelta
?
<
Stat
.
UpIndicator
/>
:
<
Stat
.
DownIndicator
/>
}
<
Stat
.
ValueText
fontWeight=
{
600
}
>
{
deltaBn
.
dp
(
8
).
toFormat
()
}
</
Stat
.
ValueText
>
</
Stat
.
Root
>
</
Skeleton
>
</
T
d
>
</
T
r
>
</
T
ableCell
>
</
T
ableRow
>
);
};
...
...
ui/pages/Address.tsx
View file @
a51725d0
...
...
@@ -2,8 +2,8 @@ import { Box, Flex, HStack } from '@chakra-ui/react';
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
import
type
{
TabItemRegular
}
from
'
toolkit/components/AdaptiveTabs/types
'
;
import
type
{
EntityTag
}
from
'
ui/shared/EntityTags/types
'
;
import
type
{
RoutedTab
}
from
'
ui/shared/Tabs/types
'
;
import
config
from
'
configs/app
'
;
import
getCheckedSummedAddress
from
'
lib/address/getCheckedSummedAddress
'
;
...
...
@@ -151,7 +151,7 @@ const AddressPageContent = () => {
Boolean(config.features.mudFramework.isEnabled && mudTablesCountQuery.data && mudTablesCountQuery.data > 0),
);
const tabs: Array<
RoutedTab
> = React.useMemo(() => {
const tabs: Array<
TabItemRegular
> = React.useMemo(() => {
return [
// config.features.mudFramework.isEnabled && mudTablesCountQuery.data && mudTablesCountQuery.data > 0 && {
// id: 'mud',
...
...
@@ -213,19 +213,19 @@ const AddressPageContent = () => {
// count: addressTabsCountersQuery.data?.celo_election_rewards_count,
// component: <AddressEpochRewards scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
// } : undefined,
//
{
//
id: 'coin_balance_history',
//
title: 'Coin balance history',
//
component: <AddressCoinBalance shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
//
},
//
addressTabsCountersQuery.data?.validations_count ?
//
{
//
id: 'blocks_validated',
//
title: `
Blocks
$
{
getNetworkValidationActionText
()
}
`,
//
count: addressTabsCountersQuery.data?.validations_count,
//
component: <AddressBlocksValidated scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
//
} :
//
undefined,
{
id: 'coin_balance_history',
title: 'Coin balance history',
component: <AddressCoinBalance shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
},
addressTabsCountersQuery.data?.validations_count ?
{
id: 'blocks_validated',
title: `
Blocks
$
{
getNetworkValidationActionText
()
}
`,
count: addressTabsCountersQuery.data?.validations_count,
component: <AddressBlocksValidated scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
} :
undefined,
// addressTabsCountersQuery.data?.logs_count ?
// {
// id: 'logs',
...
...
ui/shared/chart/ChartAxis.tsx
View file @
a51725d0
import
{
use
ColorModeValue
,
use
Token
}
from
'
@chakra-ui/react
'
;
import
{
useToken
}
from
'
@chakra-ui/react
'
;
import
*
as
d3
from
'
d3
'
;
import
React
from
'
react
'
;
import
{
useColorModeValue
}
from
'
toolkit/chakra/color-mode
'
;
interface
Props
extends
Omit
<
React
.
SVGProps
<
SVGGElement
>
,
'
scale
'
>
{
type
:
'
left
'
|
'
bottom
'
;
scale
:
d3
.
ScaleTime
<
number
,
number
>
|
d3
.
ScaleLinear
<
number
,
number
>
;
...
...
@@ -14,8 +16,7 @@ interface Props extends Omit<React.SVGProps<SVGGElement>, 'scale'> {
const
ChartAxis
=
({
type
,
scale
,
ticks
,
tickFormatGenerator
,
noAnimation
,
anchorEl
,
...
props
}:
Props
)
=>
{
const
ref
=
React
.
useRef
<
SVGGElement
>
(
null
);
const
textColorToken
=
useColorModeValue
(
'
blackAlpha.600
'
,
'
whiteAlpha.500
'
);
const
textColor
=
useToken
(
'
colors
'
,
textColorToken
);
const
textColor
=
useToken
(
'
colors
'
,
useColorModeValue
(
'
blackAlpha.600
'
,
'
whiteAlpha.500
'
));
React
.
useEffect
(()
=>
{
if
(
!
ref
.
current
)
{
...
...
@@ -41,7 +42,7 @@ const ChartAxis = ({ type, scale, ticks, tickFormatGenerator, noAnimation, ancho
axisGroup
.
selectAll
(
'
text
'
)
.
attr
(
'
opacity
'
,
1
)
.
attr
(
'
color
'
,
textColor
)
.
attr
(
'
font-size
'
,
'
0.75rem
'
);
.
style
(
'
font-size
'
,
'
12px
'
);
},
[
scale
,
ticks
,
tickFormatGenerator
,
noAnimation
,
type
,
textColor
]);
React
.
useEffect
(()
=>
{
...
...
ui/shared/chart/ChartMenu.tsx
View file @
a51725d0
import
{
IconButton
,
MenuButton
,
MenuItem
,
MenuList
,
useClipboard
,
useColorModeValue
,
VisuallyHidden
,
}
from
'
@chakra-ui/react
'
;
import
{
useCopyToClipboard
}
from
'
@uidotdev/usehooks
'
;
import
domToImage
from
'
dom-to-image
'
;
import
React
from
'
react
'
;
...
...
@@ -16,8 +8,10 @@ import type { Resolution } from '@blockscout/stats-types';
import
dayjs
from
'
lib/date/dayjs
'
;
import
isBrowser
from
'
lib/isBrowser
'
;
import
saveAsCSV
from
'
lib/saveAsCSV
'
;
import
Menu
from
'
ui/shared/chakra/Menu
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
useColorModeValue
}
from
'
toolkit/chakra/color-mode
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
MenuContent
,
MenuItem
,
MenuRoot
,
MenuTrigger
}
from
'
toolkit/chakra/menu
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
FullscreenChartModal
from
'
./FullscreenChartModal
'
;
...
...
@@ -52,19 +46,15 @@ const ChartMenu = ({
handleZoomReset
,
}:
Props
)
=>
{
const
pngBackgroundColor
=
useColorModeValue
(
'
white
'
,
'
black
'
);
const
[
isFullscreen
,
setIsFullscreen
]
=
React
.
useState
(
false
);
const
fullscreenDialog
=
useDisclosure
(
);
const
{
onCopy
}
=
useClipboard
(
chartUrl
??
''
);
const
[
,
copyToClipboard
]
=
useCopyToClipboard
(
);
const
isInBrowser
=
isBrowser
();
const
showChartFullscreen
=
React
.
useCallback
(()
=>
{
setIsFullscreen
(
true
);
},
[]);
const
clearFullscreenChart
=
React
.
useCallback
(()
=>
{
setIsFullscreen
(
false
);
},
[]);
fullscreenDialog
.
onOpenChange
({
open
:
true
});
},
[
fullscreenDialog
]);
const
handleFileSaveClick
=
React
.
useCallback
(()
=>
{
// wait for context menu to close
...
...
@@ -111,6 +101,10 @@ const ChartMenu = ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const
hasShare
=
isInBrowser
&&
(
window
.
navigator
.
share
as
any
);
const
handleCopy
=
React
.
useCallback
(()
=>
{
copyToClipboard
(
chartUrl
??
''
);
},
[
chartUrl
,
copyToClipboard
]);
const
handleShare
=
React
.
useCallback
(
async
()
=>
{
try
{
await
window
.
navigator
.
share
({
...
...
@@ -123,27 +117,17 @@ const ChartMenu = ({
return
(
<>
<
Menu
>
<
Skeleton
isLoaded=
{
!
isLoading
}
borderRadius=
"base"
>
<
MenuButton
w=
"36px"
h=
"32px"
icon=
{
<
IconSvg
name=
"dots"
boxSize=
{
4
}
transform=
"rotate(-90deg)"
/>
}
colorScheme=
"gray"
variant=
"simple"
as=
{
IconButton
}
>
<
VisuallyHidden
>
Open chart options menu
</
VisuallyHidden
>
</
MenuButton
>
</
Skeleton
>
<
MenuList
>
<
MenuRoot
>
<
MenuTrigger
asChild
>
<
IconButton
variant=
"dropdown"
size=
"sm"
aria
-
label=
"Open chart options menu"
loading=
{
isLoading
}
borderRadius=
"base"
borderWidth=
"0"
>
<
IconSvg
name=
"dots"
boxSize=
{
4
}
transform=
"rotate(-90deg)"
/>
</
IconButton
>
</
MenuTrigger
>
<
MenuContent
>
{
chartUrl
&&
(
<
MenuItem
display=
"flex"
alignItems=
"center"
onClick=
{
hasShare
?
handleShare
:
onCopy
}
value=
{
hasShare
?
'
share
'
:
'
copy
'
}
onClick=
{
hasShare
?
handleShare
:
handleCopy
}
closeOnSelect=
{
hasShare
?
false
:
true
}
>
<
IconSvg
name=
{
hasShare
?
'
share
'
:
'
copy
'
}
boxSize=
{
5
}
mr=
{
3
}
/>
...
...
@@ -151,38 +135,35 @@ const ChartMenu = ({
</
MenuItem
>
)
}
<
MenuItem
display=
"flex"
alignItems=
"center"
value=
"fullscreen"
onClick=
{
showChartFullscreen
}
>
<
IconSvg
name=
"scope"
boxSize=
{
5
}
mr=
{
3
}
/>
View fullscreen
</
MenuItem
>
<
MenuItem
display=
"flex"
alignItems=
"center"
value=
"save-png"
onClick=
{
handleFileSaveClick
}
>
<
IconSvg
name=
"files/image"
boxSize=
{
5
}
mr=
{
3
}
/>
Save as PNG
</
MenuItem
>
<
MenuItem
display=
"flex"
alignItems=
"center"
value=
"save-csv"
onClick=
{
handleSVGSavingClick
}
>
<
IconSvg
name=
"files/csv"
boxSize=
{
5
}
mr=
{
3
}
/>
Save as CSV
</
MenuItem
>
</
Menu
Lis
t
>
</
Menu
>
{
items
&&
isFullscreen
&&
(
</
Menu
Conten
t
>
</
Menu
Root
>
{
items
&&
(
<
FullscreenChartModal
isOpen
open=
{
fullscreenDialog
.
open
}
onOpenChange=
{
fullscreenDialog
.
onOpenChange
}
items=
{
items
}
title=
{
title
}
description=
{
description
}
onClose=
{
clearFullscreenChart
}
units=
{
units
}
resolution=
{
resolution
}
zoomRange=
{
zoomRange
}
...
...
ui/shared/chart/ChartWatermarkIcon.tsx
View file @
a51725d0
import
type
{
IconProps
}
from
'
@chakra-ui/react
'
;
import
{
Icon
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
Icon
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
// eslint-disable-next-line no-restricted-imports
import
logoIcon
from
'
icons/networks/logo-placeholder.svg
'
;
const
ChartWatermarkIcon
=
(
props
:
IconProps
)
=>
{
const
watermarkColor
=
useColorModeValue
(
'
link
'
,
'
white
'
);
return
(
<
Icon
{
...
props
}
...
...
@@ -18,7 +17,7 @@ const ChartWatermarkIcon = (props: IconProps) => {
transform=
"translate(-50%, -50%)"
pointerEvents=
"none"
viewBox=
"0 0 114 20"
color=
{
watermarkColor
}
color=
{
{
_light
:
'
link
'
,
_dark
:
'
white
'
}
}
/>
);
};
...
...
ui/shared/chart/ChartWidget.tsx
View file @
a51725d0
import
{
chakra
,
Flex
,
IconButton
,
Tooltip
,
useColorModeValue
,
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Flex
}
from
'
@chakra-ui/react
'
;
import
NextLink
from
'
next/link
'
;
import
React
,
{
useRef
}
from
'
react
'
;
...
...
@@ -13,7 +7,9 @@ import type { TimeChartItem } from './types';
import
{
route
,
type
Route
}
from
'
nextjs-routes
'
;
import
config
from
'
configs/app
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
ChartMenu
from
'
./ChartMenu
'
;
...
...
@@ -48,8 +44,6 @@ const ChartWidget = ({
const
ref
=
useRef
<
HTMLDivElement
>
(
null
);
const
{
zoomRange
,
handleZoom
,
handleZoomReset
}
=
useZoom
();
const
borderColor
=
useColorModeValue
(
'
gray.200
'
,
'
gray.600
'
);
const
hasItems
=
items
&&
items
.
length
>
2
;
const
content
=
(
...
...
@@ -72,24 +66,22 @@ const ChartWidget = ({
flexDir=
"column"
alignItems=
"flex-start"
cursor=
{
href
?
'
pointer
'
:
'
default
'
}
_hover=
{
href
?
{
color
:
'
link
_
hovered
'
}
:
{}
}
_hover=
{
href
?
{
color
:
'
link
.primary.
hovered
'
}
:
{}
}
>
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
fontWeight=
{
600
}
size=
{
{
base
:
'
xs
'
,
lg
:
'
sm
'
}
}
textStyle=
"md"
>
<
span
>
{
title
}
</
span
>
</
Skeleton
>
{
description
&&
(
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
color=
"text_secondary"
fontSize=
"xs"
mt=
{
1
}
>
<
span
>
{
description
}
</
span
>
</
Skeleton
>
...
...
@@ -104,8 +96,8 @@ const ChartWidget = ({
flexDir=
"column"
padding=
{
{
base
:
3
,
lg
:
4
}
}
borderRadius=
"lg"
border=
"1px"
borderColor=
{
borderColor
}
border
Width
=
"1px"
borderColor=
{
{
_light
:
'
gray.200
'
,
_dark
:
'
gray.600
'
}
}
className=
{
className
}
>
<
Flex
columnGap=
{
6
}
mb=
{
2
}
alignItems=
"flex-start"
>
...
...
@@ -115,18 +107,18 @@ const ChartWidget = ({
</
NextLink
>
)
:
chartHeader
}
<
Flex
ml=
"auto"
columnGap=
{
2
}
>
<
Tooltip
label
=
"Reset zoom"
>
<
Tooltip
content
=
"Reset zoom"
>
<
IconButton
hidden=
{
!
zoomRange
}
aria
-
label=
"Reset zoom"
colorScheme=
"blue"
w=
{
9
}
h=
{
8
}
size=
"sm"
variant=
"outline"
onClick=
{
handleZoomReset
}
icon=
{
<
IconSvg
name=
"repeat"
w=
{
4
}
h=
{
4
}
/>
}
/>
>
<
IconSvg
name=
"repeat"
boxSize=
{
4
}
/>
</
IconButton
>
</
Tooltip
>
{
hasItems
&&
(
...
...
ui/shared/chart/ChartWidgetContent.tsx
View file @
a51725d0
import
{
Box
,
Center
,
Flex
,
Link
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Center
,
Flex
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
TimeChartItem
}
from
'
./types
'
;
import
type
{
Resolution
}
from
'
@blockscout/stats-types
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
ChartWatermarkIcon
from
'
./ChartWatermarkIcon
'
;
import
ChartWidgetGraph
from
'
./ChartWidgetGraph
'
;
...
...
@@ -48,7 +49,7 @@ const ChartWidgetContent = ({
py=
{
4
}
>
<
Text
variant=
"
secondary"
color=
"text.
secondary"
fontSize=
"sm"
textAlign=
"center"
>
...
...
@@ -60,13 +61,13 @@ const ChartWidgetContent = ({
}
if
(
isLoading
)
{
return
<
Skeleton
flexGrow=
{
1
}
w=
"100%"
/>;
return
<
Skeleton
loading
flexGrow=
{
1
}
w=
"100%"
/>;
}
if
(
!
hasItems
)
{
return
(
<
Center
flexGrow=
{
1
}
>
<
Text
variant=
"
secondary"
fontSize=
"sm"
>
{
emptyText
||
'
No data
'
}
</
Text
>
<
Text
color=
"text.
secondary"
fontSize=
"sm"
>
{
emptyText
||
'
No data
'
}
</
Text
>
</
Center
>
);
}
...
...
ui/shared/chart/ChartWidgetGraph.tsx
View file @
a51725d0
...
...
@@ -41,7 +41,7 @@ const ChartWidgetGraph = ({
zoomRange
,
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
const
color
=
useToken
(
'
colors
'
,
'
blue.200
'
);
const
[
color
]
=
useToken
(
'
colors
'
,
'
blue.200
'
);
const
chartId
=
`chart-
${
title
.
split
(
'
'
).
join
(
''
)
}
-
${
isEnlarged
?
'
fullscreen
'
:
'
small
'
}
`
;
const
overlayRef
=
React
.
useRef
<
SVGRectElement
>
(
null
);
...
...
ui/shared/chart/FullscreenChartModal.tsx
View file @
a51725d0
import
{
Box
,
Button
,
Grid
,
Heading
,
Modal
,
ModalBody
,
ModalCloseButton
,
ModalContent
,
ModalOverlay
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
Grid
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
type
{
TimeChartItem
}
from
'
./types
'
;
import
type
{
Resolution
}
from
'
@blockscout/stats-types
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
DialogBody
,
DialogContent
,
DialogHeader
,
DialogRoot
}
from
'
toolkit/chakra/dialog
'
;
import
{
Heading
}
from
'
toolkit/chakra/heading
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
ChartWidgetContent
from
'
./ChartWidgetContent
'
;
type
Props
=
{
isOpen
:
boolean
;
open
:
boolean
;
onOpenChange
:
({
open
}:
{
open
:
boolean
})
=>
void
;
title
:
string
;
description
?:
string
;
items
:
Array
<
TimeChartItem
>
;
onClose
:
()
=>
void
;
units
?:
string
;
resolution
?:
Resolution
;
zoomRange
?:
[
Date
,
Date
];
...
...
@@ -22,46 +25,35 @@ type Props = {
};
const
FullscreenChartModal
=
({
isOpen
,
open
,
onOpenChange
,
title
,
description
,
items
,
units
,
onClose
,
resolution
,
zoomRange
,
handleZoom
,
handleZoomReset
,
}:
Props
)
=>
{
return
(
<
Modal
isOpen=
{
isO
pen
}
on
Close=
{
onClos
e
}
<
DialogRoot
open=
{
o
pen
}
on
OpenChange=
{
onOpenChang
e
}
size=
"full"
isCentered
>
<
ModalOverlay
/>
<
ModalContent
>
<
Box
mb=
{
1
}
>
<
Grid
gridColumnGap=
{
2
}
>
<
Heading
mb=
{
1
}
size=
{
{
base
:
'
xs
'
,
sm
:
'
md
'
}
}
>
<
DialogContent
>
<
DialogHeader
/>
<
DialogBody
pt=
{
6
}
display=
"flex"
flexDir=
"column"
>
<
Grid
gridColumnGap=
{
2
}
>
<
Heading
mb=
{
1
}
level=
"2"
>
{
title
}
</
Heading
>
{
description
&&
(
<
Text
gridColumn=
{
1
}
as=
"p"
variant=
"secondary"
color=
"text.secondary"
fontSize=
"xs"
>
{
description
}
...
...
@@ -70,8 +62,6 @@ const FullscreenChartModal = ({
{
Boolean
(
zoomRange
)
&&
(
<
Button
leftIcon=
{
<
IconSvg
name=
"repeat"
w=
{
4
}
h=
{
4
}
/>
}
colorScheme=
"blue"
gridColumn=
{
2
}
justifySelf=
"end"
alignSelf=
"top"
...
...
@@ -80,18 +70,11 @@ const FullscreenChartModal = ({
variant=
"outline"
onClick=
{
handleZoomReset
}
>
<
IconSvg
name=
"repeat"
w=
{
4
}
h=
{
4
}
/>
Reset zoom
</
Button
>
)
}
</
Grid
>
</
Box
>
<
ModalCloseButton
/>
<
ModalBody
h=
"100%"
margin=
{
{
bottom
:
60
}
}
>
<
ChartWidgetContent
isEnlarged
items=
{
items
}
...
...
@@ -101,9 +84,9 @@ const FullscreenChartModal = ({
title=
{
title
}
resolution=
{
resolution
}
/>
</
Modal
Body
>
</
Modal
Content
>
</
Modal
>
</
Dialog
Body
>
</
Dialog
Content
>
</
DialogRoot
>
);
};
...
...
ui/txs/TxsTableItem.tsx
View file @
a51725d0
...
...
@@ -71,7 +71,7 @@ const TxsTableItem = ({ tx, showBlockInfo, currentAddress, enableTimeIncrement,
</
TableCell
>
<
TableCell
whiteSpace=
"nowrap"
>
{
tx
.
method
&&
(
<
Badge
color
Schem
e=
{
tx
.
method
===
'
Multicall
'
?
'
teal
'
:
'
gray
'
}
loading=
{
isLoading
}
truncated
>
<
Badge
color
Palett
e=
{
tx
.
method
===
'
Multicall
'
?
'
teal
'
:
'
gray
'
}
loading=
{
isLoading
}
truncated
>
<
span
>
{
tx
.
method
}
</
span
>
</
Badge
>
)
}
...
...
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