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
6aba61a4
Commit
6aba61a4
authored
Feb 26, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
marketplace apps page
parent
4aaf1f1a
Changes
29
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
414 additions
and
535 deletions
+414
-535
useGraphLinks.tsx
lib/hooks/useGraphLinks.tsx
+1
-1
index.tsx
pages/apps/index.tsx
+2
-2
AppSecurityReport.tsx
ui/marketplace/AppSecurityReport.tsx
+33
-29
FeaturedApp.tsx
ui/marketplace/Banner/FeaturedApp.tsx
+24
-21
FeaturedAppMobile.tsx
ui/marketplace/Banner/FeaturedAppMobile.tsx
+25
-19
IframeBanner.tsx
ui/marketplace/Banner/IframeBanner.tsx
+7
-7
ContractListModal.tsx
ui/marketplace/ContractListModal.tsx
+21
-38
ContractSecurityReport.tsx
ui/marketplace/ContractSecurityReport.tsx
+14
-20
EmptySearchResult.tsx
ui/marketplace/EmptySearchResult.tsx
+2
-2
FavoriteIcon.tsx
ui/marketplace/FavoriteIcon.tsx
+5
-5
MarketplaceAppCard.tsx
ui/marketplace/MarketplaceAppCard.tsx
+38
-29
MarketplaceAppCardLink.tsx
ui/marketplace/MarketplaceAppCardLink.tsx
+1
-1
MarketplaceAppGraphLinks.tsx
ui/marketplace/MarketplaceAppGraphLinks.tsx
+19
-24
MarketplaceAppIntegrationIcon.tsx
ui/marketplace/MarketplaceAppIntegrationIcon.tsx
+3
-6
MarketplaceAppModal.tsx
ui/marketplace/MarketplaceAppModal.tsx
+61
-59
MarketplaceAppModalLink.tsx
ui/marketplace/MarketplaceAppModalLink.tsx
+0
-40
MarketplaceDisclaimerModal.tsx
ui/marketplace/MarketplaceDisclaimerModal.tsx
+24
-37
MarketplaceList.tsx
ui/marketplace/MarketplaceList.tsx
+3
-1
PopoverContent.tsx
ui/marketplace/Rating/PopoverContent.tsx
+1
-1
Rating.tsx
ui/marketplace/Rating/Rating.tsx
+18
-25
Stars.tsx
ui/marketplace/Rating/Stars.tsx
+2
-3
TriggerButton.tsx
ui/marketplace/Rating/TriggerButton.tsx
+45
-55
useRatings.tsx
ui/marketplace/Rating/useRatings.tsx
+8
-13
utils.ts
ui/marketplace/utils.ts
+2
-2
Marketplace.tsx
ui/pages/Marketplace.tsx
+49
-37
PinInput.tsx
ui/shared/chakra/PinInput.tsx
+0
-10
Popover.tsx
ui/shared/chakra/Popover.tsx
+0
-10
Tag.tsx
ui/shared/chakra/Tag.tsx
+0
-34
SolidityscanReportButton.tsx
ui/shared/solidityscanReport/SolidityscanReportButton.tsx
+6
-4
No files found.
lib/hooks/useGraphLinks.tsx
View file @
6aba61a4
...
@@ -9,7 +9,7 @@ const feature = config.features.marketplace;
...
@@ -9,7 +9,7 @@ const feature = config.features.marketplace;
export
default
function
useGraphLinks
()
{
export
default
function
useGraphLinks
()
{
const
fetch
=
useFetch
();
const
fetch
=
useFetch
();
return
useQuery
<
unknown
,
ResourceError
<
unknown
>
,
Record
<
string
,
Array
<
{
t
ext
:
string
;
url
:
string
}
>>>
({
return
useQuery
<
unknown
,
ResourceError
<
unknown
>
,
Record
<
string
,
Array
<
{
t
itle
:
string
;
url
:
string
}
>>>
({
queryKey
:
[
'
graph-links
'
],
queryKey
:
[
'
graph-links
'
],
queryFn
:
async
()
=>
fetch
((
feature
.
isEnabled
&&
feature
.
graphLinksUrl
)
?
feature
.
graphLinksUrl
:
''
,
undefined
,
{
resource
:
'
graph-links
'
}),
queryFn
:
async
()
=>
fetch
((
feature
.
isEnabled
&&
feature
.
graphLinksUrl
)
?
feature
.
graphLinksUrl
:
''
,
undefined
,
{
resource
:
'
graph-links
'
}),
enabled
:
feature
.
isEnabled
&&
Boolean
(
feature
.
graphLinksUrl
),
enabled
:
feature
.
isEnabled
&&
Boolean
(
feature
.
graphLinksUrl
),
...
...
pages/apps/index.tsx
View file @
6aba61a4
...
@@ -4,11 +4,11 @@ import React from 'react';
...
@@ -4,11 +4,11 @@ import React from 'react';
import
PageNextJs
from
'
nextjs/PageNextJs
'
;
import
PageNextJs
from
'
nextjs/PageNextJs
'
;
//
const Marketplace = dynamic(() => import('ui/pages/Marketplace'), { ssr: false });
const
Marketplace
=
dynamic
(()
=>
import
(
'
ui/pages/Marketplace
'
),
{
ssr
:
false
});
const
Page
:
NextPage
=
()
=>
(
const
Page
:
NextPage
=
()
=>
(
<
PageNextJs
pathname=
"/apps"
>
<
PageNextJs
pathname=
"/apps"
>
{
/* <Marketplace/> */
}
<
Marketplace
/>
</
PageNextJs
>
</
PageNextJs
>
);
);
...
...
ui/marketplace/AppSecurityReport.tsx
View file @
6aba61a4
import
{
Box
,
Text
,
Link
,
PopoverTrigger
,
PopoverBody
,
PopoverContent
,
useDisclosure
,
chakra
,
Flex
,
Divider
,
Icon
}
from
'
@chakra-ui/react
'
;
import
type
{
BoxProps
,
ButtonProps
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Text
,
Flex
,
Separator
,
Icon
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
MarketplaceAppSecurityReport
}
from
'
types/client/marketplace
'
;
import
type
{
MarketplaceAppSecurityReport
}
from
'
types/client/marketplace
'
;
...
@@ -11,7 +12,9 @@ import config from 'configs/app';
...
@@ -11,7 +12,9 @@ import config from 'configs/app';
import
solidityScanIcon
from
'
icons/brands/solidity_scan.svg
'
;
import
solidityScanIcon
from
'
icons/brands/solidity_scan.svg
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
Popover
from
'
ui/shared/chakra/Popover
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
PopoverBody
,
PopoverContent
,
PopoverRoot
}
from
'
toolkit/chakra/popover
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
SolidityscanReportButton
from
'
ui/shared/solidityscanReport/SolidityscanReportButton
'
;
import
SolidityscanReportButton
from
'
ui/shared/solidityscanReport/SolidityscanReportButton
'
;
import
SolidityscanReportDetails
from
'
ui/shared/solidityscanReport/SolidityscanReportDetails
'
;
import
SolidityscanReportDetails
from
'
ui/shared/solidityscanReport/SolidityscanReportDetails
'
;
...
@@ -24,29 +27,32 @@ type Props = {
...
@@ -24,29 +27,32 @@ type Props = {
isLoading
?:
boolean
;
isLoading
?:
boolean
;
onlyIcon
?:
boolean
;
onlyIcon
?:
boolean
;
source
:
'
Discovery view
'
|
'
App modal
'
|
'
App page
'
;
source
:
'
Discovery view
'
|
'
App modal
'
|
'
App page
'
;
className
?:
string
;
popoverPlacement
?:
'
bottom-start
'
|
'
bottom-end
'
|
'
left
'
;
popoverPlacement
?:
'
bottom-start
'
|
'
bottom-end
'
|
'
left
'
;
buttonProps
?:
ButtonProps
;
triggerWrapperProps
?:
BoxProps
;
};
};
const
AppSecurityReport
=
({
const
AppSecurityReport
=
({
id
,
securityReport
,
showContractList
,
isLoading
,
onlyIcon
,
source
,
className
,
popoverPlacement
=
'
bottom-start
'
,
id
,
securityReport
,
showContractList
,
isLoading
,
onlyIcon
,
source
,
triggerWrapperProps
,
buttonProps
,
popoverPlacement
=
'
bottom-start
'
,
}:
Props
)
=>
{
}:
Props
)
=>
{
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
const
{
open
,
onOpenChange
}
=
useDisclosure
();
const
handleButtonClick
=
React
.
useCallback
(()
=>
{
const
handleButtonClick
=
React
.
useCallback
(()
=>
{
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Security score
'
,
Info
:
id
,
Source
:
source
});
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Security score
'
,
Info
:
id
,
Source
:
source
});
onToggle
();
},
[
id
,
source
]);
},
[
id
,
source
,
onToggle
]);
const
showAnalyzedContracts
=
React
.
useCallback
(()
=>
{
const
showAnalyzedContracts
=
React
.
useCallback
(()
=>
{
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Analyzed contracts
'
,
Info
:
id
,
Source
:
'
Security score popup
'
});
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Analyzed contracts
'
,
Info
:
id
,
Source
:
'
Security score popup
'
});
showContractList
(
id
,
ContractListTypes
.
ANALYZED
);
showContractList
(
id
,
ContractListTypes
.
ANALYZED
);
},
[
showContractList
,
id
]);
onOpenChange
({
open
:
false
});
},
[
showContractList
,
id
,
onOpenChange
]);
const
showAllContracts
=
React
.
useCallback
(()
=>
{
const
showAllContracts
=
React
.
useCallback
(()
=>
{
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Total contracts
'
,
Info
:
id
,
Source
:
'
Security score popup
'
});
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Total contracts
'
,
Info
:
id
,
Source
:
'
Security score popup
'
});
showContractList
(
id
,
ContractListTypes
.
ALL
);
showContractList
(
id
,
ContractListTypes
.
ALL
);
},
[
showContractList
,
id
]);
onOpenChange
({
open
:
false
});
},
[
showContractList
,
id
,
onOpenChange
]);
const
{
const
{
securityScore
=
0
,
securityScore
=
0
,
...
@@ -60,31 +66,29 @@ const AppSecurityReport = ({
...
@@ -60,31 +66,29 @@ const AppSecurityReport = ({
}
}
return
(
return
(
<
Popover
isOpen=
{
isOpen
}
onClose=
{
onClose
}
placement=
{
popoverPlacement
}
isLazy
>
<
PopoverRoot
open=
{
open
}
onOpenChange=
{
onOpenChange
}
positioning=
{
{
placement
:
popoverPlacement
}
}
>
<
PopoverTrigger
>
<
SolidityscanReportButton
<
SolidityscanReportButton
score=
{
securityScore
}
score=
{
securityScore
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
onClick=
{
handleButtonClick
}
onClick=
{
handleButtonClick
}
onlyIcon=
{
onlyIcon
}
isActive=
{
isOpen
}
label=
{
<>
The security score is based on analysis
<
br
/>
of a DApp
{
apos
}
s smart contracts.
</>
}
onlyIcon=
{
onlyIcon
}
wrapperProps=
{
triggerWrapperProps
}
label=
{
<>
The security score is based on analysis
<
br
/>
of a DApp
{
apos
}
s smart contracts.
</>
}
{
...
buttonProps
}
className=
{
className
}
/>
/>
<
PopoverContent
w=
{
{
base
:
'
calc(100vw - 48px)
'
,
lg
:
'
328px
'
}
}
mx=
{
{
base
:
3
,
lg
:
0
}
}
>
</
PopoverTrigger
>
<
PopoverBody
px=
"26px"
py=
"20px"
textStyle=
"sm"
>
<
PopoverContent
w=
{
{
base
:
'
calc(100vw - 24px)
'
,
lg
:
'
328px
'
}
}
mx=
{
{
base
:
3
,
lg
:
0
}
}
>
<
Text
fontWeight=
"500"
textStyle=
"xs"
mb=
{
2
}
color=
"text.secondary"
>
Smart contracts info
</
Text
>
<
PopoverBody
px=
"26px"
py=
"20px"
fontSize=
"sm"
>
<
Text
fontWeight=
"500"
fontSize=
"xs"
mb=
{
2
}
variant=
"secondary"
>
Smart contracts info
</
Text
>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
py=
{
1.5
}
>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
py=
{
1.5
}
>
<
Flex
alignItems=
"center"
>
<
Flex
alignItems=
"center"
>
<
IconSvg
name=
"contracts/verified_many"
boxSize=
{
5
}
color=
"green.500"
mr=
{
1
}
/>
<
IconSvg
name=
"contracts/verified_many"
boxSize=
{
5
}
color=
"green.500"
mr=
{
1
}
/>
<
Text
>
Verified contracts
</
Text
>
<
Text
>
Verified contracts
</
Text
>
</
Flex
>
</
Flex
>
<
Link
fontSiz
e=
"sm"
fontWeight=
"500"
onClick=
{
showAllContracts
}
>
<
Link
textStyl
e=
"sm"
fontWeight=
"500"
onClick=
{
showAllContracts
}
>
{
securityReport
?.
overallInfo
.
verifiedNumber
??
0
}
of
{
securityReport
?.
overallInfo
.
totalContractsNumber
??
0
}
{
securityReport
?.
overallInfo
.
verifiedNumber
??
0
}
of
{
securityReport
?.
overallInfo
.
totalContractsNumber
??
0
}
</
Link
>
</
Link
>
</
Flex
>
</
Flex
>
<
Divide
r
my=
{
3
}
/>
<
Separato
r
my=
{
3
}
/>
<
Box
mb=
{
5
}
>
<
Box
mb=
{
5
}
>
{
solidityScanContractsNumber
}
smart contract
{
solidityScanContractsNumber
===
1
?
'
was
'
:
'
s were
'
}
evaluated to determine
{
solidityScanContractsNumber
}
smart contract
{
solidityScanContractsNumber
===
1
?
'
was
'
:
'
s were
'
}
evaluated to determine
this protocol
{
apos
}
s overall security score on the
{
config
.
chain
.
name
}
network by
{
'
'
}
this protocol
{
apos
}
s overall security score on the
{
config
.
chain
.
name
}
network by
{
'
'
}
...
@@ -96,7 +100,7 @@ const AppSecurityReport = ({
...
@@ -96,7 +100,7 @@ const AppSecurityReport = ({
<
SolidityscanReportScore
score=
{
securityScore
}
mb=
{
5
}
/>
<
SolidityscanReportScore
score=
{
securityScore
}
mb=
{
5
}
/>
{
issueSeverityDistribution
&&
totalIssues
>
0
&&
(
{
issueSeverityDistribution
&&
totalIssues
>
0
&&
(
<
Box
mb=
{
5
}
>
<
Box
mb=
{
5
}
>
<
Text
py=
"7px"
variant=
"secondary"
fontSiz
e=
"xs"
fontWeight=
{
500
}
>
Threat score
&
vulnerabilities
</
Text
>
<
Text
py=
"7px"
color=
"text.secondary"
textStyl
e=
"xs"
fontWeight=
{
500
}
>
Threat score
&
vulnerabilities
</
Text
>
<
SolidityscanReportDetails
vulnerabilities=
{
issueSeverityDistribution
}
vulnerabilitiesCount=
{
totalIssues
}
/>
<
SolidityscanReportDetails
vulnerabilities=
{
issueSeverityDistribution
}
vulnerabilitiesCount=
{
totalIssues
}
/>
</
Box
>
</
Box
>
)
}
)
}
...
@@ -105,8 +109,8 @@ const AppSecurityReport = ({
...
@@ -105,8 +109,8 @@ const AppSecurityReport = ({
</
Link
>
</
Link
>
</
PopoverBody
>
</
PopoverBody
>
</
PopoverContent
>
</
PopoverContent
>
</
Popover
>
</
Popover
Root
>
);
);
};
};
export
default
chakra
(
AppSecurityReport
)
;
export
default
AppSecurityReport
;
ui/marketplace/Banner/FeaturedApp.tsx
View file @
6aba61a4
import
{
Link
,
useColorModeValue
,
LinkBox
,
Flex
,
Image
,
LinkOverlay
,
IconButton
}
from
'
@chakra-ui/react
'
;
import
{
Link
Box
,
Flex
,
LinkOverlay
}
from
'
@chakra-ui/react
'
;
import
type
{
MouseEvent
}
from
'
react
'
;
import
type
{
MouseEvent
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
...
@@ -6,7 +6,11 @@ import type { MarketplaceAppPreview } from 'types/client/marketplace';
...
@@ -6,7 +6,11 @@ import type { MarketplaceAppPreview } from 'types/client/marketplace';
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
useColorModeValue
}
from
'
toolkit/chakra/color-mode
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Image
}
from
'
toolkit/chakra/image
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
NextLink
from
'
ui/shared/NextLink
'
;
import
NextLink
from
'
ui/shared/NextLink
'
;
import
FavoriteIcon
from
'
../FavoriteIcon
'
;
import
FavoriteIcon
from
'
../FavoriteIcon
'
;
...
@@ -32,8 +36,6 @@ const FeaturedApp = ({
...
@@ -32,8 +36,6 @@ const FeaturedApp = ({
const
logoUrl
=
useColorModeValue
(
logo
,
logoDarkMode
||
logo
);
const
logoUrl
=
useColorModeValue
(
logo
,
logoDarkMode
||
logo
);
const
categoriesLabel
=
categories
.
join
(
'
,
'
);
const
categoriesLabel
=
categories
.
join
(
'
,
'
);
const
backgroundColor
=
useColorModeValue
(
'
purple.50
'
,
'
whiteAlpha.100
'
);
const
handleInfoClick
=
useCallback
((
event
:
MouseEvent
)
=>
{
const
handleInfoClick
=
useCallback
((
event
:
MouseEvent
)
=>
{
event
.
preventDefault
();
event
.
preventDefault
();
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
More button
'
,
Info
:
id
,
Source
:
'
Banner
'
});
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
More button
'
,
Info
:
id
,
Source
:
'
Banner
'
});
...
@@ -64,12 +66,12 @@ const FeaturedApp = ({
...
@@ -64,12 +66,12 @@ const FeaturedApp = ({
borderRadius=
"md"
borderRadius=
"md"
height=
"136px"
height=
"136px"
padding=
{
5
}
padding=
{
5
}
background=
{
backgroundColor
}
background=
{
{
_light
:
'
purple.50
'
,
_dark
:
'
whiteAlpha.100
'
}
}
mb=
{
2
}
mb=
{
2
}
mt=
{
6
}
mt=
{
6
}
>
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
w=
"96px"
w=
"96px"
h=
"96px"
h=
"96px"
display=
"flex"
display=
"flex"
...
@@ -86,14 +88,14 @@ const FeaturedApp = ({
...
@@ -86,14 +88,14 @@ const FeaturedApp = ({
<
Flex
flexDirection=
"column"
flex=
{
1
}
gap=
{
2
}
>
<
Flex
flexDirection=
"column"
flex=
{
1
}
gap=
{
2
}
>
<
Flex
alignItems=
"center"
gap=
{
3
}
>
<
Flex
alignItems=
"center"
gap=
{
3
}
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
fontSize=
"30px"
fontSize=
"30px"
fontWeight=
"semibold"
fontWeight=
"semibold"
fontFamily=
"heading"
fontFamily=
"heading"
lineHeight=
"36px"
lineHeight=
"36px"
>
>
{
external
?
(
{
external
?
(
<
LinkOverlay
href=
{
url
}
isExternal=
{
true
}
marginRight=
{
2
}
>
<
LinkOverlay
href=
{
url
}
target=
"_blank"
marginRight=
{
2
}
>
{
title
}
{
title
}
</
LinkOverlay
>
</
LinkOverlay
>
)
:
(
)
:
(
...
@@ -107,7 +109,7 @@ const FeaturedApp = ({
...
@@ -107,7 +109,7 @@ const FeaturedApp = ({
</
Skeleton
>
</
Skeleton
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
color=
"text_secondary"
color=
"text_secondary"
fontSize=
"xs"
fontSize=
"xs"
flex=
{
1
}
flex=
{
1
}
...
@@ -128,25 +130,26 @@ const FeaturedApp = ({
...
@@ -128,25 +130,26 @@ const FeaturedApp = ({
{
!
isLoading
&&
(
{
!
isLoading
&&
(
<
IconButton
<
IconButton
display=
"flex"
alignItems=
"center"
aria
-
label=
"Mark as favorite"
aria
-
label=
"Mark as favorite"
title=
"Mark as favorite"
title=
"Mark as favorite"
variant=
"ghost"
// TODO @tom2drum fix this button
colorScheme=
"gray"
boxSize=
{
8
}
w=
{
9
}
h=
{
8
}
onClick=
{
handleFavoriteClick
}
onClick=
{
handleFavoriteClick
}
icon=
{
<
FavoriteIcon
isFavorite=
{
isFavorite
}
/>
}
>
/>
<
FavoriteIcon
isFavorite=
{
isFavorite
}
/>
</
IconButton
>
)
}
)
}
</
Flex
>
</
Flex
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
fontSize=
"sm"
textStyle=
"sm"
lineHeight=
"20px"
WebkitLineClamp=
{
2
}
noOfLines=
{
2
}
style=
{
{
WebkitBoxOrient
:
'
vertical
'
,
}
}
display=
"-webkit-box"
overflow=
"hidden"
>
>
{
shortDescription
}
{
shortDescription
}
</
Skeleton
>
</
Skeleton
>
...
...
ui/marketplace/Banner/FeaturedAppMobile.tsx
View file @
6aba61a4
import
{
IconButton
,
Image
,
Link
,
LinkBox
,
useColorModeValue
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
LinkBox
,
Flex
}
from
'
@chakra-ui/react
'
;
import
type
{
MouseEvent
}
from
'
react
'
;
import
type
{
MouseEvent
}
from
'
react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
MarketplaceAppPreview
}
from
'
types/client/marketplace
'
;
import
type
{
MarketplaceAppPreview
}
from
'
types/client/marketplace
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
useColorModeValue
}
from
'
toolkit/chakra/color-mode
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Image
}
from
'
toolkit/chakra/image
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
FavoriteIcon
from
'
../FavoriteIcon
'
;
import
FavoriteIcon
from
'
../FavoriteIcon
'
;
import
MarketplaceAppCardLink
from
'
../MarketplaceAppCardLink
'
;
import
MarketplaceAppCardLink
from
'
../MarketplaceAppCardLink
'
;
...
@@ -43,7 +47,7 @@ const FeaturedAppMobile = ({
...
@@ -43,7 +47,7 @@ const FeaturedAppMobile = ({
borderRadius=
"md"
borderRadius=
"md"
padding=
{
{
base
:
3
,
sm
:
'
20px
'
}
}
padding=
{
{
base
:
3
,
sm
:
'
20px
'
}
}
role=
"group"
role=
"group"
background=
{
useColorModeValue
(
'
purple.50
'
,
'
whiteAlpha.100
'
)
}
background=
{
{
base
:
'
purple.50
'
,
sm
:
'
whiteAlpha.100
'
}
}
mt=
{
6
}
mt=
{
6
}
>
>
<
Flex
<
Flex
...
@@ -58,7 +62,7 @@ const FeaturedAppMobile = ({
...
@@ -58,7 +62,7 @@ const FeaturedAppMobile = ({
justifyContent=
"space-between"
justifyContent=
"space-between"
>
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
w=
{
{
base
:
'
64px
'
,
sm
:
'
96px
'
}
}
w=
{
{
base
:
'
64px
'
,
sm
:
'
96px
'
}
}
h=
{
{
base
:
'
64px
'
,
sm
:
'
96px
'
}
}
h=
{
{
base
:
'
64px
'
,
sm
:
'
96px
'
}
}
display=
"flex"
display=
"flex"
...
@@ -93,7 +97,7 @@ const FeaturedAppMobile = ({
...
@@ -93,7 +97,7 @@ const FeaturedAppMobile = ({
<
Flex
flexDirection=
"column"
gap=
{
2
}
>
<
Flex
flexDirection=
"column"
gap=
{
2
}
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
fontSize=
{
{
base
:
'
sm
'
,
sm
:
'
lg
'
}
}
fontSize=
{
{
base
:
'
sm
'
,
sm
:
'
lg
'
}
}
lineHeight=
{
{
base
:
'
20px
'
,
sm
:
'
28px
'
}
}
lineHeight=
{
{
base
:
'
20px
'
,
sm
:
'
28px
'
}
}
paddingRight=
{
{
base
:
'
25px
'
,
sm
:
'
110px
'
}
}
paddingRight=
{
{
base
:
'
25px
'
,
sm
:
'
110px
'
}
}
...
@@ -112,19 +116,22 @@ const FeaturedAppMobile = ({
...
@@ -112,19 +116,22 @@ const FeaturedAppMobile = ({
</
Skeleton
>
</
Skeleton
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
color=
"text_secondary"
color=
"text.secondary"
fontSize=
"xs"
textStyle=
"xs"
lineHeight=
"16px"
>
>
<
span
>
{
categoriesLabel
}
</
span
>
<
span
>
{
categoriesLabel
}
</
span
>
</
Skeleton
>
</
Skeleton
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
fontSize=
{
{
base
:
'
xs
'
,
sm
:
'
sm
'
}
}
textStyle=
"xs"
lineHeight=
"20px"
WebkitLineClamp=
{
3
}
noOfLines=
{
3
}
style=
{
{
WebkitBoxOrient
:
'
vertical
'
,
}
}
display=
"-webkit-box"
overflow=
"hidden"
>
>
{
shortDescription
}
{
shortDescription
}
</
Skeleton
>
</
Skeleton
>
...
@@ -140,13 +147,12 @@ const FeaturedAppMobile = ({
...
@@ -140,13 +147,12 @@ const FeaturedAppMobile = ({
top=
{
{
base
:
1
,
sm
:
'
18px
'
}
}
top=
{
{
base
:
1
,
sm
:
'
18px
'
}
}
aria
-
label=
"Mark as favorite"
aria
-
label=
"Mark as favorite"
title=
"Mark as favorite"
title=
"Mark as favorite"
variant=
"ghost"
// TODO @tom2drum fix this button
colorScheme=
"gray"
boxSize=
{
8
}
w=
{
9
}
h=
{
8
}
onClick=
{
onFavoriteClick
}
onClick=
{
onFavoriteClick
}
icon=
{
<
FavoriteIcon
isFavorite=
{
isFavorite
}
/>
}
>
/>
<
FavoriteIcon
isFavorite=
{
isFavorite
}
/>
</
IconButton
>
)
}
)
}
</
Flex
>
</
Flex
>
</
LinkBox
>
</
LinkBox
>
...
...
ui/marketplace/Banner/IframeBanner.tsx
View file @
6aba61a4
import
{
Link
,
Box
}
from
'
@chakra-ui/react
'
;
import
{
chakra
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
const
IframeBanner
=
({
contentUrl
,
linkUrl
}:
{
contentUrl
:
string
;
linkUrl
:
string
})
=>
{
const
IframeBanner
=
({
contentUrl
,
linkUrl
}:
{
contentUrl
:
string
;
linkUrl
:
string
})
=>
{
const
[
isFrameLoading
,
setIsFrameLoading
]
=
useState
(
true
);
const
[
isFrameLoading
,
setIsFrameLoading
]
=
useState
(
true
);
...
@@ -17,7 +18,7 @@ const IframeBanner = ({ contentUrl, linkUrl }: { contentUrl: string; linkUrl: st
...
@@ -17,7 +18,7 @@ const IframeBanner = ({ contentUrl, linkUrl }: { contentUrl: string; linkUrl: st
return
(
return
(
<
Skeleton
<
Skeleton
isLoaded=
{
!
isFrameLoading
}
loading=
{
isFrameLoading
}
position=
"relative"
position=
"relative"
h=
"136px"
h=
"136px"
w=
"100%"
w=
"100%"
...
@@ -28,8 +29,8 @@ const IframeBanner = ({ contentUrl, linkUrl }: { contentUrl: string; linkUrl: st
...
@@ -28,8 +29,8 @@ const IframeBanner = ({ contentUrl, linkUrl }: { contentUrl: string; linkUrl: st
>
>
<
Link
<
Link
href=
{
linkUrl
}
href=
{
linkUrl
}
target=
"_blank"
external
rel=
"noopener noreferrer"
noIcon
onClick=
{
handleClick
}
onClick=
{
handleClick
}
position=
"absolute"
position=
"absolute"
w=
"100%"
w=
"100%"
...
@@ -38,8 +39,7 @@ const IframeBanner = ({ contentUrl, linkUrl }: { contentUrl: string; linkUrl: st
...
@@ -38,8 +39,7 @@ const IframeBanner = ({ contentUrl, linkUrl }: { contentUrl: string; linkUrl: st
left=
{
0
}
left=
{
0
}
zIndex=
{
1
}
zIndex=
{
1
}
/>
/>
<
Box
<
chakra
.
iframe
as=
"iframe"
h=
"100%"
h=
"100%"
w=
"100%"
w=
"100%"
src=
{
contentUrl
}
src=
{
contentUrl
}
...
...
ui/marketplace/ContractListModal.tsx
View file @
6aba61a4
import
{
import
{
Box
}
from
'
@chakra-ui/react
'
;
Box
,
Modal
,
Text
,
ModalBody
,
ModalCloseButton
,
ModalContent
,
ModalHeader
,
ModalOverlay
,
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
MarketplaceAppSecurityReport
}
from
'
types/client/marketplace
'
;
import
type
{
MarketplaceAppSecurityReport
}
from
'
types/client/marketplace
'
;
import
{
ContractListTypes
}
from
'
types/client/marketplace
'
;
import
{
ContractListTypes
}
from
'
types/client/marketplace
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
{
DialogBody
,
DialogContent
,
DialogHeader
,
DialogRoot
}
from
'
toolkit/chakra/dialog
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
ContractSecurityReport
from
'
./ContractSecurityReport
'
;
import
ContractSecurityReport
from
'
./ContractSecurityReport
'
;
...
@@ -28,7 +24,11 @@ const titles = {
...
@@ -28,7 +24,11 @@ const titles = {
};
};
const
ContractListModal
=
({
onClose
,
onBack
,
type
,
contracts
}:
Props
)
=>
{
const
ContractListModal
=
({
onClose
,
onBack
,
type
,
contracts
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
const
handleOpenChange
=
React
.
useCallback
(({
open
}:
{
open
:
boolean
})
=>
{
if
(
!
open
)
{
onClose
();
}
},
[
onClose
]);
const
displayedContracts
=
React
.
useMemo
(()
=>
{
const
displayedContracts
=
React
.
useMemo
(()
=>
{
if
(
!
contracts
)
{
if
(
!
contracts
)
{
...
@@ -54,35 +54,18 @@ const ContractListModal = ({ onClose, onBack, type, contracts }: Props) => {
...
@@ -54,35 +54,18 @@ const ContractListModal = ({ onClose, onBack, type, contracts }: Props) => {
}
}
return
(
return
(
<
Modal
<
DialogRoot
isO
pen=
{
Boolean
(
type
)
}
o
pen=
{
Boolean
(
type
)
}
on
Close=
{
onClos
e
}
on
OpenChange=
{
handleOpenChang
e
}
size=
{
isMobile
?
'
full
'
:
'
md
'
}
size=
{
{
lgDown
:
'
full
'
,
lg
:
'
md
'
}
}
isCentered
placement=
"center"
>
>
<
ModalOverlay
/>
<
DialogContent
>
<
ModalContent
>
<
DialogHeader
display=
"flex"
alignItems=
"center"
mb=
{
4
}
onBackToClick=
{
onBack
}
>
<
ModalHeader
display=
"flex"
alignItems=
"center"
mb=
{
4
}
>
{
titles
[
type
]
}
{
onBack
&&
(
</
DialogHeader
>
<
IconSvg
<
DialogBody
name=
"arrows/east"
maxH=
{
{
base
:
'
max-content
'
,
lg
:
'
352px
'
}
}
w=
{
6
}
h=
{
10
}
transform=
"rotate(180deg)"
verticalAlign=
"middle"
color=
"gray.400"
mr=
{
3
}
cursor=
"pointer"
onClick=
{
onBack
}
/>
)
}
<
Text
fontWeight=
"500"
textStyle=
"h3"
>
{
titles
[
type
]
}
</
Text
>
</
ModalHeader
>
<
ModalCloseButton
/>
<
ModalBody
maxH=
{
isMobile
?
'
auto
'
:
'
352px
'
}
overflow=
"scroll"
overflow=
"scroll"
mb=
{
0
}
mb=
{
0
}
display=
"grid"
display=
"grid"
...
@@ -110,9 +93,9 @@ const ContractListModal = ({ onClose, onBack, type, contracts }: Props) => {
...
@@ -110,9 +93,9 @@ const ContractListModal = ({ onClose, onBack, type, contracts }: Props) => {
/>
/>
</
React
.
Fragment
>
</
React
.
Fragment
>
))
}
))
}
</
Modal
Body
>
</
Dialog
Body
>
</
Modal
Content
>
</
Dialog
Content
>
</
Modal
>
</
DialogRoot
>
);
);
};
};
...
...
ui/marketplace/ContractSecurityReport.tsx
View file @
6aba61a4
import
{
Box
,
Text
,
PopoverTrigger
,
PopoverBody
,
PopoverContent
,
useDisclosure
,
Icon
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Text
,
Icon
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
...
@@ -8,8 +8,8 @@ import config from 'configs/app';
...
@@ -8,8 +8,8 @@ import config from 'configs/app';
import
solidityScanIcon
from
'
icons/brands/solidity_scan.svg
'
;
import
solidityScanIcon
from
'
icons/brands/solidity_scan.svg
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
type
{
SolidityScanReport
}
from
'
lib/solidityScan/schema
'
;
import
type
{
SolidityScanReport
}
from
'
lib/solidityScan/schema
'
;
import
Popover
from
'
ui/shared/chakra/Popover
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
import
{
PopoverBody
,
PopoverContent
,
PopoverRoot
}
from
'
toolkit/chakra/popover
'
;
import
SolidityscanReportButton
from
'
ui/shared/solidityscanReport/SolidityscanReportButton
'
;
import
SolidityscanReportButton
from
'
ui/shared/solidityscanReport/SolidityscanReportButton
'
;
import
SolidityscanReportDetails
from
'
ui/shared/solidityscanReport/SolidityscanReportDetails
'
;
import
SolidityscanReportDetails
from
'
ui/shared/solidityscanReport/SolidityscanReportDetails
'
;
import
SolidityscanReportScore
from
'
ui/shared/solidityscanReport/SolidityscanReportScore
'
;
import
SolidityscanReportScore
from
'
ui/shared/solidityscanReport/SolidityscanReportScore
'
;
...
@@ -19,12 +19,9 @@ type Props = {
...
@@ -19,12 +19,9 @@ type Props = {
};
};
const
ContractSecurityReport
=
({
securityReport
}:
Props
)
=>
{
const
ContractSecurityReport
=
({
securityReport
}:
Props
)
=>
{
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
const
handleClick
=
React
.
useCallback
(()
=>
{
const
handleClick
=
React
.
useCallback
(()
=>
{
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Security score
'
,
Source
:
'
Analyzed contracts popup
'
});
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Security score
'
,
Source
:
'
Analyzed contracts popup
'
});
onToggle
();
},
[
]);
},
[
onToggle
]);
if
(
!
securityReport
)
{
if
(
!
securityReport
)
{
return
null
;
return
null
;
...
@@ -39,16 +36,13 @@ const ContractSecurityReport = ({ securityReport }: Props) => {
...
@@ -39,16 +36,13 @@ const ContractSecurityReport = ({ securityReport }: Props) => {
const
totalIssues
=
Object
.
values
(
issueSeverityDistribution
as
Record
<
string
,
number
>
).
reduce
((
acc
,
val
)
=>
acc
+
val
,
0
);
const
totalIssues
=
Object
.
values
(
issueSeverityDistribution
as
Record
<
string
,
number
>
).
reduce
((
acc
,
val
)
=>
acc
+
val
,
0
);
return
(
return
(
<
Popover
isOpen=
{
isOpen
}
onClose=
{
onClose
}
placement=
"bottom-start"
isLazy
>
<
PopoverRoot
>
<
PopoverTrigger
>
<
SolidityscanReportButton
<
SolidityscanReportButton
score=
{
parseFloat
(
securityScore
)
}
score=
{
parseFloat
(
securityScore
)
}
onClick=
{
handleClick
}
onClick=
{
handleClick
}
/>
isActive=
{
isOpen
}
<
PopoverContent
>
/>
<
PopoverBody
>
</
PopoverTrigger
>
<
PopoverContent
w=
{
{
base
:
'
100vw
'
,
lg
:
'
328px
'
}
}
>
<
PopoverBody
px=
"26px"
py=
"20px"
fontSize=
"sm"
>
<
Box
mb=
{
5
}
>
<
Box
mb=
{
5
}
>
The security score was derived from evaluating the smart contracts of a protocol on the
{
config
.
chain
.
name
}
network by
{
'
'
}
The security score was derived from evaluating the smart contracts of a protocol on the
{
config
.
chain
.
name
}
network by
{
'
'
}
<
Box
>
<
Box
>
...
@@ -59,14 +53,14 @@ const ContractSecurityReport = ({ securityReport }: Props) => {
...
@@ -59,14 +53,14 @@ const ContractSecurityReport = ({ securityReport }: Props) => {
<
SolidityscanReportScore
score=
{
parseFloat
(
securityScore
)
}
mb=
{
5
}
/>
<
SolidityscanReportScore
score=
{
parseFloat
(
securityScore
)
}
mb=
{
5
}
/>
{
issueSeverityDistribution
&&
totalIssues
>
0
&&
(
{
issueSeverityDistribution
&&
totalIssues
>
0
&&
(
<
Box
mb=
{
5
}
>
<
Box
mb=
{
5
}
>
<
Text
py=
"7px"
variant=
"secondary"
fontSiz
e=
"xs"
fontWeight=
{
500
}
>
Threat score
&
vulnerabilities
</
Text
>
<
Text
py=
"7px"
color=
"text.secondary"
textStyl
e=
"xs"
fontWeight=
{
500
}
>
Threat score
&
vulnerabilities
</
Text
>
<
SolidityscanReportDetails
vulnerabilities=
{
issueSeverityDistribution
}
vulnerabilitiesCount=
{
totalIssues
}
/>
<
SolidityscanReportDetails
vulnerabilities=
{
issueSeverityDistribution
}
vulnerabilitiesCount=
{
totalIssues
}
/>
</
Box
>
</
Box
>
)
}
)
}
<
Link
External
href=
{
url
}
>
View full report
</
LinkExternal
>
<
Link
external
href=
{
url
}
>
View full report
</
Link
>
</
PopoverBody
>
</
PopoverBody
>
</
PopoverContent
>
</
PopoverContent
>
</
Popover
>
</
Popover
Root
>
);
);
};
};
...
...
ui/marketplace/EmptySearchResult.tsx
View file @
6aba61a4
...
@@ -4,9 +4,9 @@ import { MarketplaceCategory } from 'types/client/marketplace';
...
@@ -4,9 +4,9 @@ import { MarketplaceCategory } from 'types/client/marketplace';
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
EmptySearchResultDefault
from
'
ui/shared/EmptySearchResult
'
;
import
EmptySearchResultDefault
from
'
ui/shared/EmptySearchResult
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
const
feature
=
config
.
features
.
marketplace
;
const
feature
=
config
.
features
.
marketplace
;
...
@@ -29,7 +29,7 @@ const EmptySearchResult = ({ favoriteApps, selectedCategoryId }: Props) => (
...
@@ -29,7 +29,7 @@ const EmptySearchResult = ({ favoriteApps, selectedCategoryId }: Props) => (
{
'
suggestIdeasFormUrl
'
in
feature
&&
(
{
'
suggestIdeasFormUrl
'
in
feature
&&
(
<>
<>
{
'
'
}
Have a groundbreaking idea or app suggestion?
<
br
/>
{
'
'
}
Have a groundbreaking idea or app suggestion?
<
br
/>
<
Link
External
href=
{
feature
.
suggestIdeasFormUrl
}
>
Share it with us
</
LinkExternal
>
<
Link
external
href=
{
feature
.
suggestIdeasFormUrl
}
>
Share it with us
</
Link
>
</>
</>
)
}
)
}
</>
</>
...
...
ui/marketplace/FavoriteIcon.tsx
View file @
6aba61a4
import
{
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
type
{
HTMLChakraProps
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
type
Props
=
{
interface
Props
extends
HTMLChakraProps
<
'
div
'
>
{
isFavorite
:
boolean
;
isFavorite
:
boolean
;
color
?:
string
;
};
};
const
FavoriteIcon
=
({
isFavorite
,
color
}:
Props
)
=>
{
const
FavoriteIcon
=
({
isFavorite
,
color
,
...
rest
}:
Props
)
=>
{
const
heartFilledColor
=
useColorModeValue
(
'
blue.600
'
,
'
blue.300
'
)
;
const
heartFilledColor
=
{
_light
:
'
blue.600
'
,
_dark
:
'
blue.300
'
}
;
const
defaultColor
=
isFavorite
?
heartFilledColor
:
(
color
||
'
gray.400
'
);
const
defaultColor
=
isFavorite
?
heartFilledColor
:
(
color
||
'
gray.400
'
);
return
(
return
(
...
@@ -17,6 +16,7 @@ const FavoriteIcon = ({ isFavorite, color }: Props) => {
...
@@ -17,6 +16,7 @@ const FavoriteIcon = ({ isFavorite, color }: Props) => {
name=
{
isFavorite
?
'
heart_filled
'
:
'
heart_outline
'
}
name=
{
isFavorite
?
'
heart_filled
'
:
'
heart_outline
'
}
color=
{
defaultColor
}
color=
{
defaultColor
}
boxSize=
{
5
}
boxSize=
{
5
}
{
...
rest
}
/>
/>
);
);
};
};
...
...
ui/marketplace/MarketplaceAppCard.tsx
View file @
6aba61a4
import
{
IconButton
,
Image
,
Link
,
LinkBox
,
useColorModeValue
,
chakra
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
LinkBox
,
chakra
,
Flex
}
from
'
@chakra-ui/react
'
;
import
type
{
MouseEvent
}
from
'
react
'
;
import
type
{
MouseEvent
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
...
@@ -6,7 +6,11 @@ import type { MarketplaceAppWithSecurityReport, ContractListTypes, AppRating } f
...
@@ -6,7 +6,11 @@ import type { MarketplaceAppWithSecurityReport, ContractListTypes, AppRating } f
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
isBrowser
from
'
lib/isBrowser
'
;
import
isBrowser
from
'
lib/isBrowser
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
useColorModeValue
}
from
'
toolkit/chakra/color-mode
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Image
}
from
'
toolkit/chakra/image
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
AppSecurityReport
from
'
./AppSecurityReport
'
;
import
AppSecurityReport
from
'
./AppSecurityReport
'
;
...
@@ -30,7 +34,7 @@ interface Props extends MarketplaceAppWithSecurityReport {
...
@@ -30,7 +34,7 @@ interface Props extends MarketplaceAppWithSecurityReport {
isRatingSending
:
boolean
;
isRatingSending
:
boolean
;
isRatingLoading
:
boolean
;
isRatingLoading
:
boolean
;
canRate
:
boolean
|
undefined
;
canRate
:
boolean
|
undefined
;
graphLinks
:
Array
<
{
text
:
string
;
url
:
string
}
>
;
graphLinks
?:
Array
<
{
title
:
string
;
url
:
string
}
>
;
}
}
const
MarketplaceAppCard
=
({
const
MarketplaceAppCard
=
({
...
@@ -84,9 +88,8 @@ const MarketplaceAppCard = ({
...
@@ -84,9 +88,8 @@ const MarketplaceAppCard = ({
}
}
}
}
borderRadius=
"md"
borderRadius=
"md"
padding=
{
{
base
:
3
,
md
:
'
20px
'
}
}
padding=
{
{
base
:
3
,
md
:
'
20px
'
}
}
border=
"1px"
borderWidth=
"1px"
borderColor=
{
useColorModeValue
(
'
gray.200
'
,
'
gray.600
'
)
}
borderColor=
{
{
_light
:
'
gray.200
'
,
_dark
:
'
gray.600
'
}
}
role=
"group"
>
>
<
Flex
<
Flex
flexDirection=
"column"
flexDirection=
"column"
...
@@ -99,7 +102,7 @@ const MarketplaceAppCard = ({
...
@@ -99,7 +102,7 @@ const MarketplaceAppCard = ({
gap=
{
4
}
gap=
{
4
}
>
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
w=
{
{
base
:
'
64px
'
,
md
:
'
96px
'
}
}
w=
{
{
base
:
'
64px
'
,
md
:
'
96px
'
}
}
h=
{
{
base
:
'
64px
'
,
md
:
'
96px
'
}
}
h=
{
{
base
:
'
64px
'
,
md
:
'
96px
'
}
}
display=
"flex"
display=
"flex"
...
@@ -121,9 +124,10 @@ const MarketplaceAppCard = ({
...
@@ -121,9 +124,10 @@ const MarketplaceAppCard = ({
pt=
{
1
}
pt=
{
1
}
>
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
paddingRight=
{
{
base
:
'
40px
'
,
md
:
0
}
}
paddingRight=
{
{
base
:
'
40px
'
,
md
:
0
}
}
display=
"inline-block"
display=
"inline-flex"
alignItems=
"center"
>
>
<
MarketplaceAppCardLink
<
MarketplaceAppCardLink
id=
{
id
}
id=
{
id
}
...
@@ -141,12 +145,11 @@ const MarketplaceAppCard = ({
...
@@ -141,12 +145,11 @@ const MarketplaceAppCard = ({
links=
{
graphLinks
}
links=
{
graphLinks
}
ml=
{
2
}
ml=
{
2
}
verticalAlign=
"middle"
verticalAlign=
"middle"
mb=
{
{
base
:
0
,
md
:
1
}
}
/>
/>
</
Skeleton
>
</
Skeleton
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
color=
"text_secondary"
color=
"text_secondary"
fontSize=
"xs"
fontSize=
"xs"
lineHeight=
"16px"
lineHeight=
"16px"
...
@@ -157,10 +160,14 @@ const MarketplaceAppCard = ({
...
@@ -157,10 +160,14 @@ const MarketplaceAppCard = ({
</
Flex
>
</
Flex
>
<
Skeleton
<
Skeleton
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
fontSize=
"sm"
textStyle=
"sm"
lineHeight=
"20px"
WebkitLineClamp=
{
{
base
:
2
,
md
:
3
}
}
noOfLines=
{
{
base
:
2
,
md
:
3
}
}
style=
{
{
WebkitBoxOrient
:
'
vertical
'
,
}
}
display=
"-webkit-box"
overflow=
"hidden"
>
>
{
shortDescription
}
{
shortDescription
}
</
Skeleton
>
</
Skeleton
>
...
@@ -172,7 +179,7 @@ const MarketplaceAppCard = ({
...
@@ -172,7 +179,7 @@ const MarketplaceAppCard = ({
marginTop=
"auto"
marginTop=
"auto"
>
>
<
Link
<
Link
fontSiz
e=
"sm"
textStyl
e=
"sm"
fontWeight=
"500"
fontWeight=
"500"
paddingRight=
{
{
md
:
2
}
}
paddingRight=
{
{
md
:
2
}
}
href=
"#"
href=
"#"
...
@@ -196,20 +203,18 @@ const MarketplaceAppCard = ({
...
@@ -196,20 +203,18 @@ const MarketplaceAppCard = ({
title=
"Mark as favorite"
title=
"Mark as favorite"
variant=
"ghost"
variant=
"ghost"
colorScheme=
"gray"
colorScheme=
"gray"
w=
{
{
base
:
6
,
md
:
'
30px
'
}
}
boxSize=
{
{
base
:
6
,
md
:
'
30px
'
}
}
h=
{
{
base
:
6
,
md
:
'
30px
'
}
}
onClick=
{
handleFavoriteClick
}
onClick=
{
handleFavoriteClick
}
icon=
{
<
FavoriteIcon
isFavorite=
{
isFavorite
}
/>
}
ml=
{
2
}
ml=
{
2
}
/>
>
<
FavoriteIcon
isFavorite=
{
isFavorite
}
/>
</
IconButton
>
<
CopyToClipboard
<
CopyToClipboard
text=
{
isBrowser
()
?
window
.
location
.
origin
+
`/apps/${ id }`
:
''
}
text=
{
isBrowser
()
?
window
.
location
.
origin
+
`/apps/${ id }`
:
''
}
icon
=
"share"
type
=
"share"
size=
{
4
}
boxSize=
{
{
base
:
6
,
md
:
'
30px
'
}
}
variant=
"ghost"
variant=
"ghost"
colorScheme=
"gray"
colorScheme=
"gray"
w=
{
{
base
:
6
,
md
:
'
30px
'
}
}
h=
{
{
base
:
6
,
md
:
'
30px
'
}
}
color=
"gray.400"
color=
"gray.400"
_hover=
{
{
color
:
'
gray.400
'
}
}
_hover=
{
{
color
:
'
gray.400
'
}
}
ml=
{
{
base
:
1
,
md
:
0
}
}
ml=
{
{
base
:
1
,
md
:
0
}
}
...
@@ -228,11 +233,15 @@ const MarketplaceAppCard = ({
...
@@ -228,11 +233,15 @@ const MarketplaceAppCard = ({
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
source=
"Discovery view"
source=
"Discovery view"
popoverPlacement=
{
isMobile
?
'
bottom-end
'
:
'
left
'
}
popoverPlacement=
{
isMobile
?
'
bottom-end
'
:
'
left
'
}
position=
"absolute"
triggerWrapperProps=
{
{
right=
{
{
base
:
3
,
md
:
5
}
}
position
:
'
absolute
'
,
top=
{
{
base
:
'
10px
'
,
md
:
5
}
}
right
:
{
base
:
3
,
md
:
5
},
border=
{
0
}
top
:
{
base
:
'
10px
'
,
md
:
5
},
padding=
{
0
}
}
}
buttonProps=
{
{
border
:
0
,
padding
:
0
,
}
}
/>
/>
)
}
)
}
</
Flex
>
</
Flex
>
...
...
ui/marketplace/MarketplaceAppCardLink.tsx
View file @
6aba61a4
...
@@ -19,7 +19,7 @@ const MarketplaceAppCardLink = ({ url, external, id, title, onClick, className }
...
@@ -19,7 +19,7 @@ const MarketplaceAppCardLink = ({ url, external, id, title, onClick, className }
},
[
onClick
,
id
]);
},
[
onClick
,
id
]);
return
external
?
(
return
external
?
(
<
LinkOverlay
href=
{
url
}
isExternal=
{
true
}
marginRight=
{
2
}
className=
{
className
}
>
<
LinkOverlay
href=
{
url
}
marginRight=
{
2
}
className=
{
className
}
>
{
title
}
{
title
}
</
LinkOverlay
>
</
LinkOverlay
>
)
:
(
)
:
(
...
...
ui/marketplace/MarketplaceAppGraphLinks.tsx
View file @
6aba61a4
import
{
import
{
Text
,
Text
,
PopoverTrigger
,
PopoverBody
,
PopoverContent
,
chakra
,
chakra
,
Box
,
Box
,
VStack
,
VStack
,
...
@@ -10,9 +7,9 @@ import {
...
@@ -10,9 +7,9 @@ import {
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
Popover
from
'
ui/shared/chakra/Popover
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
interface
Props
{
interface
Props
{
className
?:
string
;
className
?:
string
;
...
@@ -30,27 +27,25 @@ const MarketplaceAppGraphLinks = ({ className, links }: Props) => {
...
@@ -30,27 +27,25 @@ const MarketplaceAppGraphLinks = ({ className, links }: Props) => {
return
null
;
return
null
;
}
}
const
content
=
(
<
VStack
gap=
{
4
}
align=
"start"
textStyle=
"sm"
w=
"260px"
>
<
Text
>
{
`This dapp uses ${ links.length > 1 ? 'several subgraphs' : 'a subgraph' } powered by The Graph`
}
</
Text
>
{
links
.
map
(
link
=>
(
<
Link
external
key=
{
link
.
url
}
href=
{
link
.
url
}
>
{
link
.
title
}
</
Link
>
))
}
</
VStack
>
);
return
(
return
(
<
Box
position=
"relative"
className=
{
className
}
display=
"inline-flex"
alignItems=
"center"
height=
{
7
}
onClick=
{
handleButtonClick
}
>
<
Box
position=
"relative"
className=
{
className
}
display=
"inline-flex"
alignItems=
"center"
onClick=
{
handleButtonClick
}
>
<
Popover
<
Tooltip
placement=
{
isMobile
?
'
bottom-end
'
:
'
bottom
'
}
variant=
"popover"
isLazy
content=
{
content
}
trigger=
"hover"
positioning=
{
{
placement
:
isMobile
?
'
bottom-end
'
:
'
bottom
'
}
}
interactive
>
>
<
PopoverTrigger
>
<
IconSvg
name=
"brands/graph"
boxSize=
{
5
}
onClick=
{
handleButtonClick
}
/>
<
IconSvg
name=
"brands/graph"
boxSize=
{
5
}
onClick=
{
handleButtonClick
}
/>
</
Tooltip
>
</
PopoverTrigger
>
<
PopoverContent
w=
"260px"
>
<
PopoverBody
fontSize=
"sm"
>
<
VStack
gap=
{
4
}
align=
"start"
>
<
Text
>
{
`This dapp uses ${ links.length > 1 ? 'several subgraphs' : 'a subgraph' } powered by The Graph`
}
</
Text
>
{
links
.
map
(
link
=>
(
<
LinkExternal
key=
{
link
.
url
}
href=
{
link
.
url
}
>
{
link
.
title
}
</
LinkExternal
>
))
}
</
VStack
>
</
PopoverBody
>
</
PopoverContent
>
</
Popover
>
</
Box
>
</
Box
>
);
);
};
};
...
...
ui/marketplace/MarketplaceAppIntegrationIcon.tsx
View file @
6aba61a4
import
{
Tooltip
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
type
{
IconName
}
from
'
ui/shared/IconSvg
'
;
import
type
{
IconName
}
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
...
@@ -32,11 +32,9 @@ const MarketplaceAppIntegrationIcon = ({ external, internalWallet }: Props) => {
...
@@ -32,11 +32,9 @@ const MarketplaceAppIntegrationIcon = ({ external, internalWallet }: Props) => {
return
(
return
(
<
Tooltip
<
Tooltip
label=
{
text
}
content=
{
text
}
textAlign=
"center"
padding=
{
2
}
openDelay=
{
300
}
openDelay=
{
300
}
maxW=
{
{
base
:
'
calc(100vw - 8px)
'
,
lg
:
'
400px
'
}
}
contentProps=
{
{
maxW
:
{
base
:
'
calc(100vw - 8px)
'
,
lg
:
'
400px
'
}
}
}
>
>
<
IconSvg
<
IconSvg
name=
{
icon
}
name=
{
icon
}
...
@@ -45,7 +43,6 @@ const MarketplaceAppIntegrationIcon = ({ external, internalWallet }: Props) => {
...
@@ -45,7 +43,6 @@ const MarketplaceAppIntegrationIcon = ({ external, internalWallet }: Props) => {
position=
"relative"
position=
"relative"
cursor=
"pointer"
cursor=
"pointer"
verticalAlign=
"middle"
verticalAlign=
"middle"
mb=
{
{
base
:
0
,
md
:
1
}
}
/>
/>
</
Tooltip
>
</
Tooltip
>
);
);
...
...
ui/marketplace/MarketplaceAppModal.tsx
View file @
6aba61a4
import
{
import
{
Box
,
Flex
,
Text
}
from
'
@chakra-ui/react
'
;
Box
,
Flex
,
Heading
,
IconButton
,
Image
,
Link
,
Modal
,
ModalBody
,
ModalCloseButton
,
ModalContent
,
ModalFooter
,
ModalOverlay
,
Tag
,
Text
,
useColorModeValue
,
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
type
{
MarketplaceAppWithSecurityReport
,
AppRating
}
from
'
types/client/marketplace
'
;
import
type
{
MarketplaceAppWithSecurityReport
,
AppRating
}
from
'
types/client/marketplace
'
;
import
{
ContractListTypes
}
from
'
types/client/marketplace
'
;
import
{
ContractListTypes
}
from
'
types/client/marketplace
'
;
import
{
route
}
from
'
nextjs-routes
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
{
nbsp
}
from
'
lib/html-entities
'
;
import
{
nbsp
}
from
'
lib/html-entities
'
;
import
isBrowser
from
'
lib/isBrowser
'
;
import
isBrowser
from
'
lib/isBrowser
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
{
Badge
}
from
'
toolkit/chakra/badge
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
useColorModeValue
}
from
'
toolkit/chakra/color-mode
'
;
import
{
DialogBody
,
DialogCloseTrigger
,
DialogContent
,
DialogFooter
,
DialogRoot
}
from
'
toolkit/chakra/dialog
'
;
import
{
Heading
}
from
'
toolkit/chakra/heading
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Image
}
from
'
toolkit/chakra/image
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
type
{
IconName
}
from
'
ui/shared/IconSvg
'
;
import
type
{
IconName
}
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
...
@@ -20,7 +27,6 @@ import AppSecurityReport from './AppSecurityReport';
...
@@ -20,7 +27,6 @@ import AppSecurityReport from './AppSecurityReport';
import
FavoriteIcon
from
'
./FavoriteIcon
'
;
import
FavoriteIcon
from
'
./FavoriteIcon
'
;
import
MarketplaceAppGraphLinks
from
'
./MarketplaceAppGraphLinks
'
;
import
MarketplaceAppGraphLinks
from
'
./MarketplaceAppGraphLinks
'
;
import
MarketplaceAppIntegrationIcon
from
'
./MarketplaceAppIntegrationIcon
'
;
import
MarketplaceAppIntegrationIcon
from
'
./MarketplaceAppIntegrationIcon
'
;
import
MarketplaceAppModalLink
from
'
./MarketplaceAppModalLink
'
;
import
Rating
from
'
./Rating/Rating
'
;
import
Rating
from
'
./Rating/Rating
'
;
import
type
{
RateFunction
}
from
'
./Rating/useRatings
'
;
import
type
{
RateFunction
}
from
'
./Rating/useRatings
'
;
...
@@ -38,7 +44,7 @@ type Props = {
...
@@ -38,7 +44,7 @@ type Props = {
isRatingSending
:
boolean
;
isRatingSending
:
boolean
;
isRatingLoading
:
boolean
;
isRatingLoading
:
boolean
;
canRate
:
boolean
|
undefined
;
canRate
:
boolean
|
undefined
;
graphLinks
?:
Array
<
{
t
ext
:
string
;
url
:
string
}
>
;
graphLinks
?:
Array
<
{
t
itle
:
string
;
url
:
string
}
>
;
};
};
const
MarketplaceAppModal
=
({
const
MarketplaceAppModal
=
({
...
@@ -97,14 +103,23 @@ const MarketplaceAppModal = ({
...
@@ -97,14 +103,23 @@ const MarketplaceAppModal = ({
}
}
}
}
const
handleOpenChange
=
React
.
useCallback
(({
open
}:
{
open
:
boolean
})
=>
{
if
(
!
open
)
{
onClose
();
}
},
[
onClose
]);
const
handleFavoriteClick
=
useCallback
(()
=>
{
const
handleFavoriteClick
=
useCallback
(()
=>
{
onFavoriteClick
(
id
,
isFavorite
,
'
App modal
'
);
onFavoriteClick
(
id
,
isFavorite
,
'
App modal
'
);
},
[
onFavoriteClick
,
id
,
isFavorite
]);
},
[
onFavoriteClick
,
id
,
isFavorite
]);
const
showContractList
=
useCallback
((
id
:
string
,
type
:
ContractListTypes
)
=>
{
const
showContractList
=
useCallback
((
id
:
string
,
type
:
ContractListTypes
)
=>
{
onClose
();
onClose
();
showContractListProp
(
id
,
type
,
true
);
// FIXME: This is a workaround to avoid the dialog closing before the modal is opened
},
[
onClose
,
showContractListProp
]);
window
.
setTimeout
(()
=>
{
showContractListProp
(
id
,
type
,
true
);
},
100
);
},
[
showContractListProp
,
onClose
]);
const
showAllContracts
=
React
.
useCallback
(()
=>
{
const
showAllContracts
=
React
.
useCallback
(()
=>
{
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Total contracts
'
,
Info
:
id
,
Source
:
'
App modal
'
});
mixpanel
.
logEvent
(
mixpanel
.
EventTypes
.
PAGE_WIDGET
,
{
Type
:
'
Total contracts
'
,
Info
:
id
,
Source
:
'
App modal
'
});
...
@@ -120,22 +135,19 @@ const MarketplaceAppModal = ({
...
@@ -120,22 +135,19 @@ const MarketplaceAppModal = ({
}
catch
(
err
)
{}
}
catch
(
err
)
{}
}
}
const
iconColor
=
useColorModeValue
(
'
blue.600
'
,
'
gray.400
'
)
;
const
iconColor
=
{
_light
:
'
blue.600
'
,
_dark
:
'
gray.400
'
}
;
return
(
return
(
<
Modal
<
DialogRoot
isO
pen=
{
Boolean
(
data
.
id
)
}
o
pen=
{
Boolean
(
data
.
id
)
}
on
Close=
{
onClos
e
}
on
OpenChange=
{
handleOpenChang
e
}
size=
{
isMobile
?
'
full
'
:
'
md
'
}
size=
{
{
lgDown
:
'
full
'
,
lg
:
'
md
'
}
}
isCentered
placement=
"center"
>
>
<
ModalOverlay
/>
<
DialogContent
>
<
ModalContent
>
<
Box
<
Box
display=
"grid"
display=
"grid"
gridTemplateColumns=
{
{
base
:
'
auto 1fr
'
}
}
gridTemplateColumns=
{
{
base
:
'
auto 1fr
'
}
}
paddingRight=
{
{
md
:
12
}
}
marginBottom=
{
{
base
:
6
,
md
:
8
}
}
marginBottom=
{
{
base
:
6
,
md
:
8
}
}
>
>
<
Flex
<
Flex
...
@@ -155,24 +167,22 @@ const MarketplaceAppModal = ({
...
@@ -155,24 +167,22 @@ const MarketplaceAppModal = ({
<
Flex
alignItems=
"center"
mb=
{
{
md
:
2
}
}
gridColumn=
{
2
}
>
<
Flex
alignItems=
"center"
mb=
{
{
md
:
2
}
}
gridColumn=
{
2
}
>
<
Heading
<
Heading
as=
"h2"
level=
"2"
fontSize=
{
{
base
:
'
2xl
'
,
md
:
'
32px
'
}
}
fontWeight=
"medium"
fontWeight=
"medium"
lineHeight=
{
{
md
:
10
}
}
mr=
{
2
}
mr=
{
2
}
>
>
{
title
}
{
title
}
</
Heading
>
</
Heading
>
<
MarketplaceAppIntegrationIcon
external=
{
external
}
internalWallet=
{
internalWallet
}
/>
<
MarketplaceAppIntegrationIcon
external=
{
external
}
internalWallet=
{
internalWallet
}
/>
<
MarketplaceAppGraphLinks
links=
{
graphLinks
}
ml=
{
2
}
/>
<
MarketplaceAppGraphLinks
links=
{
graphLinks
}
ml=
{
2
}
/>
<
DialogCloseTrigger
ml=
"auto"
/>
</
Flex
>
</
Flex
>
<
Text
<
Text
variant=
"
secondary"
color=
"text.
secondary"
gridColumn=
{
2
}
gridColumn=
{
2
}
fontSiz
e=
{
{
base
:
'
sm
'
,
md
:
'
md
'
}
}
textStyl
e=
{
{
base
:
'
sm
'
,
md
:
'
md
'
}
}
fontWeight=
"normal"
fontWeight=
"normal"
lineHeight=
{
{
md
:
6
}
}
>
>
By
{
nbsp
}{
author
}
By
{
nbsp
}{
author
}
</
Text
>
</
Text
>
...
@@ -204,31 +214,28 @@ const MarketplaceAppModal = ({
...
@@ -204,31 +214,28 @@ const MarketplaceAppModal = ({
>
>
<
Flex
flexWrap=
"wrap"
gap=
{
6
}
>
<
Flex
flexWrap=
"wrap"
gap=
{
6
}
>
<
Flex
width=
{
{
base
:
'
100%
'
,
md
:
'
auto
'
}
}
>
<
Flex
width=
{
{
base
:
'
100%
'
,
md
:
'
auto
'
}
}
>
<
MarketplaceAppModalLink
<
Link
href=
{
external
?
url
:
route
({
pathname
:
'
/apps/[id]
'
,
query
:
{
id
:
data
.
id
}
})
}
external=
{
external
}
noIcon
>
id=
{
data
.
id
}
<
Button
size=
"sm"
mr=
{
2
}
w=
{
{
base
:
'
100%
'
,
sm
:
'
auto
'
}
}
>
url=
{
url
}
Launch app
external=
{
external
}
</
Button
>
title=
{
title
}
</
Link
>
/>
<
IconButton
<
IconButton
aria
-
label=
"Mark as favorite"
aria
-
label=
"Mark as favorite"
title=
"Mark as favorite"
title=
"Mark as favorite"
variant=
"outline"
variant=
"outline"
colorScheme=
"gray"
w=
{
9
}
w=
{
9
}
h=
{
8
}
h=
{
8
}
flexShrink=
{
0
}
flexShrink=
{
0
}
onClick=
{
handleFavoriteClick
}
onClick=
{
handleFavoriteClick
}
icon=
{
<
FavoriteIcon
isFavorite=
{
isFavorite
}
color=
{
iconColor
}
/>
}
>
/>
<
FavoriteIcon
isFavorite=
{
isFavorite
}
color=
{
iconColor
}
/>
</
IconButton
>
<
CopyToClipboard
<
CopyToClipboard
text=
{
isBrowser
()
?
window
.
location
.
origin
+
`/apps/${ id }`
:
''
}
text=
{
isBrowser
()
?
window
.
location
.
origin
+
`/apps/${ id }`
:
''
}
icon=
"share"
type=
"share"
size=
{
4
}
variant=
"outline"
variant=
"outline"
colorScheme=
"gray"
w=
{
9
}
w=
{
9
}
h=
{
8
}
h=
{
8
}
color=
{
iconColor
}
color=
{
iconColor
}
...
@@ -241,9 +248,7 @@ const MarketplaceAppModal = ({
...
@@ -241,9 +248,7 @@ const MarketplaceAppModal = ({
</
Box
>
</
Box
>
</
Box
>
</
Box
>
<
ModalCloseButton
/>
<
DialogBody
mb=
{
6
}
>
<
ModalBody
mb=
{
6
}
>
{
securityReport
&&
(
{
securityReport
&&
(
<
Flex
<
Flex
direction=
{
{
base
:
'
column
'
,
md
:
'
row
'
}
}
direction=
{
{
base
:
'
column
'
,
md
:
'
row
'
}
}
...
@@ -275,34 +280,34 @@ const MarketplaceAppModal = ({
...
@@ -275,34 +280,34 @@ const MarketplaceAppModal = ({
</
Flex
>
</
Flex
>
)
}
)
}
<
Text
>
{
description
}
</
Text
>
<
Text
>
{
description
}
</
Text
>
</
Modal
Body
>
</
Dialog
Body
>
<
Modal
Footer
<
Dialog
Footer
display=
"flex"
display=
"flex"
flexDirection=
{
{
base
:
'
column
'
,
md
:
'
row
'
}
}
flexDirection=
{
{
base
:
'
column
'
,
md
:
'
row
'
}
}
justifyContent=
{
{
base
:
'
flex-start
'
,
md
:
'
space-between
'
}
}
justifyContent=
{
{
base
:
'
flex-start
'
,
md
:
'
space-between
'
}
}
alignItems=
{
{
base
:
'
flex-start
'
,
md
:
'
center
'
}
}
alignItems=
"flex-start"
gap=
{
3
}
gap=
{
3
}
>
>
<
Flex
gap=
{
2
}
>
<
Flex
gap=
{
2
}
flexWrap=
"wrap"
>
{
categories
.
map
((
category
)
=>
(
{
categories
.
map
((
category
)
=>
(
<
Tag
<
Badge
color
Schem
e=
"blue"
color
Palett
e=
"blue"
key=
{
category
}
key=
{
category
}
>
>
{
category
}
{
category
}
</
Tag
>
</
Badge
>
))
}
))
}
</
Flex
>
</
Flex
>
<
Flex
alignItems=
"center"
gap=
{
3
}
>
<
Flex
alignItems=
"center"
gap=
{
3
}
my=
"2px"
>
{
site
&&
(
{
site
&&
(
<
Link
<
Link
isE
xternal
e
xternal
href=
{
site
}
href=
{
site
}
display=
"flex"
display=
"flex"
alignItems=
"center"
alignItems=
"center"
fontSiz
e=
"sm"
textStyl
e=
"sm"
>
>
<
IconSvg
<
IconSvg
name=
"link"
name=
"link"
...
@@ -332,23 +337,20 @@ const MarketplaceAppModal = ({
...
@@ -332,23 +337,20 @@ const MarketplaceAppModal = ({
display=
"flex"
display=
"flex"
alignItems=
"center"
alignItems=
"center"
justifyContent=
"center"
justifyContent=
"center"
isExternal
external
w=
{
5
}
flexShrink=
{
0
}
h=
{
5
}
>
>
<
IconSvg
<
IconSvg
name=
{
icon
}
name=
{
icon
}
w=
"20px"
color=
"text.secondary"
h=
"20px"
boxSize=
{
5
}
display=
"block"
color=
"text_secondary"
/>
/>
</
Link
>
</
Link
>
))
}
))
}
</
Flex
>
</
Flex
>
</
Modal
Footer
>
</
Dialog
Footer
>
</
Modal
Content
>
</
Dialog
Content
>
</
Modal
>
</
DialogRoot
>
);
);
};
};
...
...
ui/marketplace/MarketplaceAppModalLink.tsx
deleted
100644 → 0
View file @
4aaf1f1a
import
{
Button
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
NextLink
from
'
ui/shared/NextLink
'
;
type
Props
=
{
id
:
string
;
url
:
string
;
external
?:
boolean
;
title
:
string
;
};
const
MarketplaceAppModalLink
=
({
url
,
external
,
id
}:
Props
)
=>
{
const
buttonProps
=
{
size
:
'
sm
'
,
marginRight
:
2
,
width
:
{
base
:
'
100%
'
,
sm
:
'
auto
'
},
...(
external
?
{
target
:
'
_blank
'
,
rel
:
'
noopener noreferrer
'
,
}
:
{}),
};
return
external
?
(
<
Button
as=
"a"
href=
{
url
}
{
...
buttonProps
}
>
Launch app
</
Button
>
)
:
(
<
NextLink
href=
{
{
pathname
:
'
/apps/[id]
'
,
query
:
{
id
}
}
}
passHref
legacyBehavior
>
<
Button
as=
"a"
{
...
buttonProps
}
>
Launch app
</
Button
>
</
NextLink
>
);
};
export
default
MarketplaceAppModalLink
;
ui/marketplace/MarketplaceDisclaimerModal.tsx
View file @
6aba61a4
import
{
Heading
,
Modal
,
ModalBody
,
ModalContent
,
ModalFooter
,
ModalHeader
,
ModalOverlay
,
Text
,
Button
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
route
}
from
'
nextjs-routes
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
NextLink
from
'
ui/shared/NextLink
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
DialogBody
,
DialogContent
,
DialogFooter
,
DialogHeader
,
DialogRoot
}
from
'
toolkit/chakra/dialog
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
type
Props
=
{
type
Props
=
{
isOpen
:
boolean
;
isOpen
:
boolean
;
...
@@ -19,62 +23,45 @@ const MarketplaceDisclaimerModal = ({ isOpen, onClose, appId }: Props) => {
...
@@ -19,62 +23,45 @@ const MarketplaceDisclaimerModal = ({ isOpen, onClose, appId }: Props) => {
},
[
]);
},
[
]);
return
(
return
(
<
Modal
<
DialogRoot
isO
pen=
{
isOpen
}
o
pen=
{
isOpen
}
on
Clos
e=
{
onClose
}
on
OpenChang
e=
{
onClose
}
size=
{
isMobile
?
'
full
'
:
'
md
'
}
size=
{
isMobile
?
'
full
'
:
'
md
'
}
isCentered
placement=
"center"
>
>
<
ModalOverlay
/>
<
DialogContent
>
<
DialogHeader
>
<
ModalContent
>
Disclaimer
<
ModalHeader
>
</
DialogHeader
>
<
Heading
as=
"h2"
fontSize=
"2xl"
fontWeight=
"medium"
lineHeight=
{
1
}
color=
{
useColorModeValue
(
'
blackAlpha.800
'
,
'
whiteAlpha.800
'
)
}
>
Disclaimer
</
Heading
>
</
ModalHeader
>
<
Modal
Body
>
<
Dialog
Body
>
<
Text
color=
{
useColorModeValue
(
'
gray.800
'
,
'
whiteAlpha.800
'
)
}
>
<
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. Blockscout 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.
and is not liable for any losses associated with these interactions. Please do so at your own risk.
<
br
/><
br
/>
<
br
/><
br
/>
By clicking continue, you agree that you understand the risks and have read the Disclaimer.
By clicking continue, you agree that you understand the risks and have read the Disclaimer.
</
Text
>
</
Text
>
</
Modal
Body
>
</
Dialog
Body
>
<
Modal
Footer
<
Dialog
Footer
display=
"flex"
display=
"flex"
flexDirection=
"row"
flexDirection=
"row"
alignItems=
"center"
alignItems=
"center"
>
>
<
NextLink
href=
{
{
pathname
:
'
/apps/[id]
'
,
query
:
{
id
:
appId
}
}
}
passHref
legacyBehavior
>
<
Link
href=
{
route
({
pathname
:
'
/apps/[id]
'
,
query
:
{
id
:
appId
}
})
}
asChild
>
<
Button
<
Button
onClick=
{
handleContinueClick
}
>
variant=
"solid"
colorScheme=
"blue"
mr=
{
6
}
py=
"10px"
onClick=
{
handleContinueClick
}
>
Continue to app
Continue to app
</
Button
>
</
Button
>
</
Next
Link
>
</
Link
>
<
Button
<
Button
variant=
"outline"
variant=
"outline"
colorScheme=
"blue"
onClick=
{
onClose
}
onClick=
{
onClose
}
>
>
Cancel
Cancel
</
Button
>
</
Button
>
</
Modal
Footer
>
</
Dialog
Footer
>
</
Modal
Content
>
</
Dialog
Content
>
</
Modal
>
</
DialogRoot
>
);
);
};
};
...
...
ui/marketplace/MarketplaceList.tsx
View file @
6aba61a4
...
@@ -26,7 +26,7 @@ type Props = {
...
@@ -26,7 +26,7 @@ type Props = {
isRatingSending
:
boolean
;
isRatingSending
:
boolean
;
isRatingLoading
:
boolean
;
isRatingLoading
:
boolean
;
canRate
:
boolean
|
undefined
;
canRate
:
boolean
|
undefined
;
graphLinksQuery
:
UseQueryResult
<
Record
<
string
,
Array
<
{
t
ext
:
string
;
url
:
string
}
>>
,
unknown
>
;
graphLinksQuery
:
UseQueryResult
<
Record
<
string
,
Array
<
{
t
itle
:
string
;
url
:
string
}
>>
,
unknown
>
;
};
};
const
MarketplaceList
=
({
const
MarketplaceList
=
({
...
@@ -61,6 +61,8 @@ const MarketplaceList = ({
...
@@ -61,6 +61,8 @@ const MarketplaceList = ({
external=
{
app
.
external
}
external=
{
app
.
external
}
url=
{
app
.
url
}
url=
{
app
.
url
}
title=
{
app
.
title
}
title=
{
app
.
title
}
description=
{
app
.
description
}
author=
{
app
.
author
}
logo=
{
app
.
logo
}
logo=
{
app
.
logo
}
logoDarkMode=
{
app
.
logoDarkMode
}
logoDarkMode=
{
app
.
logoDarkMode
}
shortDescription=
{
app
.
shortDescription
}
shortDescription=
{
app
.
shortDescription
}
...
...
ui/marketplace/Rating/PopoverContent.tsx
View file @
6aba61a4
...
@@ -57,7 +57,7 @@ const PopoverContent = ({ appId, rating, userRating, rate, isSending, source }:
...
@@ -57,7 +57,7 @@ const PopoverContent = ({ appId, rating, userRating, rate, isSending, source }:
{
userRating
&&
(
{
userRating
&&
(
<
IconSvg
name=
"verified"
color=
"green.400"
boxSize=
"30px"
mr=
{
1
}
ml=
"-5px"
/>
<
IconSvg
name=
"verified"
color=
"green.400"
boxSize=
"30px"
mr=
{
1
}
ml=
"-5px"
/>
)
}
)
}
<
Text
fontWeight=
"500"
fontSize=
"xs"
lineHeight=
"30px"
variant=
"
secondary"
>
<
Text
fontWeight=
"500"
textStyle=
"xs"
color=
"text.
secondary"
>
{
userRating
?
'
App is already rated by you
'
:
'
How was your experience?
'
}
{
userRating
?
'
App is already rated by you
'
:
'
How was your experience?
'
}
</
Text
>
</
Text
>
</
Flex
>
</
Flex
>
...
...
ui/marketplace/Rating/Rating.tsx
View file @
6aba61a4
import
{
Text
,
PopoverTrigger
,
PopoverBody
,
PopoverContent
,
useDisclosure
,
useOutsideClick
,
Box
}
from
'
@chakra-ui/react
'
;
import
{
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
AppRating
}
from
'
types/client/marketplace
'
;
import
type
{
AppRating
}
from
'
types/client/marketplace
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
type
{
EventTypes
,
EventPayload
}
from
'
lib/mixpanel/index
'
;
import
type
{
EventTypes
,
EventPayload
}
from
'
lib/mixpanel/index
'
;
import
Popover
from
'
ui/shared/chakra/P
opover
'
;
import
{
PopoverBody
,
PopoverContent
,
PopoverRoot
}
from
'
toolkit/chakra/p
opover
'
;
import
Skeleton
from
'
ui/shared/chakra/S
keleton
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/s
keleton
'
;
import
Content
from
'
./PopoverContent
'
;
import
Content
from
'
./PopoverContent
'
;
import
Stars
from
'
./Stars
'
;
import
Stars
from
'
./Stars
'
;
...
@@ -32,10 +32,6 @@ const Rating = ({
...
@@ -32,10 +32,6 @@ const Rating = ({
appId
,
rating
,
userRating
,
rate
,
appId
,
rating
,
userRating
,
rate
,
isSending
,
isLoading
,
fullView
,
canRate
,
source
,
isSending
,
isLoading
,
fullView
,
canRate
,
source
,
}:
Props
)
=>
{
}:
Props
)
=>
{
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
// have to implement this solution because popover loses focus on button click inside it (issue: https://github.com/chakra-ui/chakra-ui/issues/7359)
const
popoverRef
=
React
.
useRef
(
null
);
useOutsideClick
({
ref
:
popoverRef
,
handler
:
onClose
});
if
(
!
isEnabled
)
{
if
(
!
isEnabled
)
{
return
null
;
return
null
;
...
@@ -45,30 +41,27 @@ const Rating = ({
...
@@ -45,30 +41,27 @@ const Rating = ({
<
Skeleton
<
Skeleton
display=
"flex"
display=
"flex"
alignItems=
"center"
alignItems=
"center"
isLoaded=
{
!
isLoading
}
loading=
{
isLoading
}
w=
{
(
isLoading
&&
!
fullView
)
?
'
40px
'
:
'
auto
'
}
w=
{
(
isLoading
&&
!
fullView
)
?
'
40px
'
:
'
auto
'
}
>
>
{
fullView
&&
(
{
fullView
&&
(
<>
<>
<
Stars
filledIndex=
{
(
rating
?.
value
||
0
)
-
1
}
/>
<
Stars
filledIndex=
{
(
rating
?.
value
||
0
)
-
1
}
/>
<
Text
fontSize=
"md"
ml=
{
2
}
>
{
rating
?.
value
}
</
Text
>
<
Text
fontSize=
"md"
ml=
{
2
}
>
{
rating
?.
value
}
</
Text
>
{
rating
?.
count
&&
<
Text
variant=
"secondary"
fontSiz
e=
"md"
ml=
{
1
}
>
(
{
rating
?.
count
}
)
</
Text
>
}
{
rating
?.
count
&&
<
Text
color=
"text.secondary"
textStyl
e=
"md"
ml=
{
1
}
>
(
{
rating
?.
count
}
)
</
Text
>
}
</>
</>
)
}
)
}
<
Box
ref=
{
popoverRef
}
>
<
PopoverRoot
positioning=
{
{
placement
:
'
bottom
'
}
}
>
<
Popover
isOpen=
{
isOpen
}
placement=
"bottom"
isLazy
>
<
PopoverTrigger
>
<
TriggerButton
<
TriggerButton
rating=
{
rating
?.
value
}
rating=
{
rating
?.
value
}
count=
{
rating
?.
count
}
count=
{
rating
?.
count
}
fullView=
{
fullView
}
fullView=
{
fullView
}
canRate=
{
canRate
}
isActive=
{
isOpen
}
/>
onClick=
{
onToggle
}
{
canRate
?
(
canRate=
{
canRate
}
<
PopoverContent
w=
"250px"
>
/>
<
PopoverBody
>
</
PopoverTrigger
>
<
PopoverContent
w=
"250px"
mx=
{
3
}
>
<
PopoverBody
p=
{
4
}
>
<
Content
<
Content
appId=
{
appId
}
appId=
{
appId
}
rating=
{
rating
}
rating=
{
rating
}
...
@@ -79,8 +72,8 @@ const Rating = ({
...
@@ -79,8 +72,8 @@ const Rating = ({
/>
/>
</
PopoverBody
>
</
PopoverBody
>
</
PopoverContent
>
</
PopoverContent
>
</
Popover
>
)
:
<
PopoverContent
/>
}
</
Box
>
</
PopoverRoot
>
</
Skeleton
>
</
Skeleton
>
);
);
};
};
...
...
ui/marketplace/Rating/Stars.tsx
View file @
6aba61a4
import
{
Flex
,
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
Flex
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
MouseEventHandler
}
from
'
react
'
;
import
type
{
MouseEventHandler
}
from
'
react
'
;
...
@@ -12,8 +12,7 @@ type Props = {
...
@@ -12,8 +12,7 @@ type Props = {
};
};
const
Stars
=
({
filledIndex
,
onMouseOverFactory
,
onMouseOut
,
onClickFactory
}:
Props
)
=>
{
const
Stars
=
({
filledIndex
,
onMouseOverFactory
,
onMouseOut
,
onClickFactory
}:
Props
)
=>
{
const
disabledStarColor
=
useColorModeValue
(
'
gray.200
'
,
'
gray.700
'
);
const
outlineStartColor
=
onMouseOverFactory
?
'
gray.400
'
:
{
_light
:
'
gray.200
'
,
_dark
:
'
gray.700
'
};
const
outlineStartColor
=
onMouseOverFactory
?
'
gray.400
'
:
disabledStarColor
;
return
(
return
(
<
Flex
>
<
Flex
>
{
Array
(
5
).
fill
(
null
).
map
((
_
,
index
)
=>
(
{
Array
(
5
).
fill
(
null
).
map
((
_
,
index
)
=>
(
...
...
ui/marketplace/Rating/TriggerButton.tsx
View file @
6aba61a4
import
{
Button
,
chakra
,
useColorModeValue
,
Tooltip
,
useDisclosure
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
usePreventFocusAfterModalClosing
from
'
lib/hooks/usePreventFocusAfterModalClosing
'
;
import
usePreventFocusAfterModalClosing
from
'
lib/hooks/usePreventFocusAfterModalClosing
'
;
import
type
{
ButtonProps
}
from
'
toolkit/chakra/button
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
PopoverTrigger
}
from
'
toolkit/chakra/popover
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
type
Props
=
{
interface
Props
extends
ButtonProps
{
rating
?:
number
;
rating
?:
number
;
count
?:
number
;
count
?:
number
;
fullView
?:
boolean
;
fullView
?:
boolean
;
isActive
:
boolean
;
onClick
:
()
=>
void
;
canRate
:
boolean
|
undefined
;
canRate
:
boolean
|
undefined
;
};
};
...
@@ -25,66 +27,54 @@ const getTooltipText = (canRate: boolean | undefined) => {
...
@@ -25,66 +27,54 @@ const getTooltipText = (canRate: boolean | undefined) => {
};
};
const
TriggerButton
=
(
const
TriggerButton
=
(
{
rating
,
count
,
fullView
,
isActive
,
onClick
,
canRate
}:
Props
,
{
rating
,
count
,
fullView
,
canRate
,
onClick
,
...
rest
}:
Props
,
ref
:
React
.
ForwardedRef
<
HTML
Button
Element
>
,
ref
:
React
.
ForwardedRef
<
HTML
Div
Element
>
,
)
=>
{
)
=>
{
const
textColor
=
useColorModeValue
(
'
blackAlpha.800
'
,
'
whiteAlpha.800
'
);
const
onFocusCapture
=
usePreventFocusAfterModalClosing
();
const
onFocusCapture
=
usePreventFocusAfterModalClosing
();
// TODO @tom2drum remove all such occurrences of useDisclosure
// have to implement controlled tooltip on mobile because of the issue - https://github.com/chakra-ui/chakra-ui/issues/7107
const
{
isOpen
,
onToggle
,
onClose
}
=
useDisclosure
();
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
const
handleClick
=
React
.
useCallback
(()
=>
{
if
(
canRate
)
{
onClick
();
}
else
if
(
isMobile
)
{
onToggle
();
}
},
[
canRate
,
isMobile
,
onToggle
,
onClick
]);
return
(
return
(
<
Tooltip
<
Tooltip
label=
{
getTooltipText
(
canRate
)
}
content=
{
getTooltipText
(
canRate
)
}
openDelay=
{
100
}
textAlign=
"center"
closeOnClick=
{
Boolean
(
canRate
)
||
isMobile
}
closeOnClick=
{
Boolean
(
canRate
)
||
isMobile
}
isOpen=
{
isMobile
?
isOpen
:
undefined
}
disableOnMobile=
{
canRate
}
>
>
<
Button
<
div
>
ref=
{
ref
}
<
PopoverTrigger
>
size=
"xs"
<
Button
variant=
"outline"
ref=
{
ref
}
border=
{
0
}
size=
"xs"
p=
{
0
}
variant=
"outline"
onClick=
{
handleClick
}
border=
{
0
}
fontSize=
{
fullView
?
'
md
'
:
'
sm
'
}
p=
{
0
}
fontWeight=
{
fullView
?
'
400
'
:
'
500
'
}
fontSize=
{
fullView
?
'
md
'
:
'
sm
'
}
lineHeight=
"21px"
fontWeight=
{
fullView
?
'
400
'
:
'
500
'
}
ml=
{
fullView
?
3
:
0
}
lineHeight=
"21px"
isActive=
{
isActive
}
ml=
{
fullView
?
3
:
0
}
onFocusCapture=
{
onFocusCapture
}
onFocusCapture=
{
onFocusCapture
}
cursor=
{
canRate
?
'
pointer
'
:
'
default
'
}
cursor=
{
canRate
?
'
pointer
'
:
'
default
'
}
onMouseLeave=
{
isMobile
?
onClose
:
undefined
}
{
...
rest
}
>
>
{
!
fullView
&&
(
{
!
fullView
&&
(
<
IconSvg
<
IconSvg
name=
{
rating
?
'
star_filled
'
:
'
star_outline
'
}
name=
{
rating
?
'
star_filled
'
:
'
star_outline
'
}
color=
{
rating
?
'
yellow.400
'
:
'
gray.400
'
}
color=
{
rating
?
'
yellow.400
'
:
'
gray.400
'
}
boxSize=
{
5
}
boxSize=
{
5
}
mr=
{
1
}
mr=
{
1
}
/>
/>
)
}
)
}
{
(
rating
&&
!
fullView
)
?
(
{
(
rating
&&
!
fullView
)
?
(
<
chakra
.
span
color=
{
textColor
}
transition=
"inherit"
display=
"inline-flex"
>
<
chakra
.
span
color=
{
{
_light
:
'
blackAlpha.800
'
,
_dark
:
'
whiteAlpha.800
'
}
}
transition=
"inherit"
display=
"inline-flex"
>
{
rating
}
{
rating
}
<
Text
variant=
"secondary"
ml=
{
1
}
>
(
{
count
}
)
</
Text
>
<
Text
color=
"text.secondary"
ml=
{
1
}
>
(
{
count
}
)
</
Text
>
</
chakra
.
span
>
</
chakra
.
span
>
)
:
(
)
:
(
'
Rate it!
'
'
Rate it!
'
)
}
)
}
</
Button
>
</
Button
>
</
PopoverTrigger
>
</
div
>
</
Tooltip
>
</
Tooltip
>
);
);
};
};
...
...
ui/marketplace/Rating/useRatings.tsx
View file @
6aba61a4
...
@@ -6,10 +6,10 @@ import type { AppRating } from 'types/client/marketplace';
...
@@ -6,10 +6,10 @@ import type { AppRating } from 'types/client/marketplace';
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
type
{
EventTypes
,
EventPayload
}
from
'
lib/mixpanel/index
'
;
import
type
{
EventTypes
,
EventPayload
}
from
'
lib/mixpanel/index
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
*
as
mixpanel
from
'
lib/mixpanel/index
'
;
import
{
ADDRESS_COUNTERS
}
from
'
stubs/address
'
;
import
{
ADDRESS_COUNTERS
}
from
'
stubs/address
'
;
import
{
toaster
}
from
'
toolkit/chakra/toaster
'
;
const
MIN_TRANSACTION_COUNT
=
5
;
const
MIN_TRANSACTION_COUNT
=
5
;
...
@@ -41,7 +41,6 @@ function formatRatings(data: Airtable.Records<Airtable.FieldSet>) {
...
@@ -41,7 +41,6 @@ function formatRatings(data: Airtable.Records<Airtable.FieldSet>) {
export
default
function
useRatings
()
{
export
default
function
useRatings
()
{
const
{
address
}
=
useAccount
();
const
{
address
}
=
useAccount
();
const
toast
=
useToast
();
const
addressCountersQuery
=
useApiQuery
<
'
address_counters
'
,
{
status
:
number
}
>
(
'
address_counters
'
,
{
const
addressCountersQuery
=
useApiQuery
<
'
address_counters
'
,
{
status
:
number
}
>
(
'
address_counters
'
,
{
pathParams
:
{
hash
:
address
},
pathParams
:
{
hash
:
address
},
...
@@ -68,13 +67,12 @@ export default function useRatings() {
...
@@ -68,13 +67,12 @@ export default function useRatings() {
const
ratings
=
formatRatings
(
data
);
const
ratings
=
formatRatings
(
data
);
setRatings
(
ratings
);
setRatings
(
ratings
);
}
catch
(
error
)
{
}
catch
(
error
)
{
toast
({
toaster
.
error
({
status
:
'
error
'
,
title
:
'
Error loading ratings
'
,
title
:
'
Error loading ratings
'
,
description
:
'
Please try again later
'
,
description
:
'
Please try again later
'
,
});
});
}
}
},
[
toast
]);
},
[
]);
useEffect
(()
=>
{
useEffect
(()
=>
{
async
function
fetch
()
{
async
function
fetch
()
{
...
@@ -97,8 +95,7 @@ export default function useRatings() {
...
@@ -97,8 +95,7 @@ export default function useRatings() {
}).
all
();
}).
all
();
userRatings
=
formatRatings
(
data
);
userRatings
=
formatRatings
(
data
);
}
catch
(
error
)
{
}
catch
(
error
)
{
toast
({
toaster
.
error
({
status
:
'
error
'
,
title
:
'
Error loading user ratings
'
,
title
:
'
Error loading user ratings
'
,
description
:
'
Please try again later
'
,
description
:
'
Please try again later
'
,
});
});
...
@@ -108,7 +105,7 @@ export default function useRatings() {
...
@@ -108,7 +105,7 @@ export default function useRatings() {
setIsUserRatingLoading
(
false
);
setIsUserRatingLoading
(
false
);
}
}
fetchUserRatings
();
fetchUserRatings
();
},
[
address
,
toast
]);
},
[
address
]);
useEffect
(()
=>
{
useEffect
(()
=>
{
const
isPlaceholderData
=
addressCountersQuery
?.
isPlaceholderData
;
const
isPlaceholderData
=
addressCountersQuery
?.
isPlaceholderData
;
...
@@ -163,8 +160,7 @@ export default function useRatings() {
...
@@ -163,8 +160,7 @@ export default function useRatings() {
});
});
fetchRatings
();
fetchRatings
();
toast
({
toaster
.
success
({
status
:
'
success
'
,
title
:
'
Awesome! Thank you 💜
'
,
title
:
'
Awesome! Thank you 💜
'
,
description
:
'
Your rating improves the service
'
,
description
:
'
Your rating improves the service
'
,
});
});
...
@@ -173,15 +169,14 @@ export default function useRatings() {
...
@@ -173,15 +169,14 @@ export default function useRatings() {
{
Action
:
'
Rating
'
,
Source
:
source
,
AppId
:
appId
,
Score
:
rating
},
{
Action
:
'
Rating
'
,
Source
:
source
,
AppId
:
appId
,
Score
:
rating
},
);
);
}
catch
(
error
)
{
}
catch
(
error
)
{
toast
({
toaster
.
error
({
status
:
'
error
'
,
title
:
'
Ooops! Something went wrong
'
,
title
:
'
Ooops! Something went wrong
'
,
description
:
'
Please try again later
'
,
description
:
'
Please try again later
'
,
});
});
}
}
setIsSending
(
false
);
setIsSending
(
false
);
},
[
address
,
userRatings
,
fetchRatings
,
toast
]);
},
[
address
,
userRatings
,
fetchRatings
]);
return
{
return
{
ratings
,
ratings
,
...
...
ui/marketplace/utils.ts
View file @
6aba61a4
...
@@ -7,10 +7,10 @@ import type { SelectOption } from 'toolkit/chakra/select';
...
@@ -7,10 +7,10 @@ import type { SelectOption } from 'toolkit/chakra/select';
const
feature
=
config
.
features
.
marketplace
;
const
feature
=
config
.
features
.
marketplace
;
export
type
SortValue
=
'
rating_score
'
|
'
rating_count
'
|
'
security_score
'
;
export
type
SortValue
=
'
default
'
|
'
rating_score
'
|
'
rating_count
'
|
'
security_score
'
;
export
const
SORT_OPTIONS
:
Array
<
SelectOption
<
SortValue
>>
=
[
export
const
SORT_OPTIONS
:
Array
<
SelectOption
<
SortValue
>>
=
[
{
label
:
'
Default
'
,
value
:
undefined
},
{
label
:
'
Default
'
,
value
:
'
default
'
},
(
feature
.
isEnabled
&&
feature
.
rating
)
&&
{
label
:
'
Top rated
'
,
value
:
'
rating_score
'
},
(
feature
.
isEnabled
&&
feature
.
rating
)
&&
{
label
:
'
Top rated
'
,
value
:
'
rating_score
'
},
(
feature
.
isEnabled
&&
feature
.
rating
)
&&
{
label
:
'
Most rated
'
,
value
:
'
rating_count
'
},
(
feature
.
isEnabled
&&
feature
.
rating
)
&&
{
label
:
'
Most rated
'
,
value
:
'
rating_count
'
},
(
feature
.
isEnabled
&&
feature
.
securityReportsUrl
)
&&
{
label
:
'
Security score
'
,
value
:
'
security_score
'
},
(
feature
.
isEnabled
&&
feature
.
securityReportsUrl
)
&&
{
label
:
'
Security score
'
,
value
:
'
security_score
'
},
...
...
ui/pages/Marketplace.tsx
View file @
6aba61a4
import
{
MenuButton
,
MenuItem
,
MenuList
,
Flex
,
IconButton
}
from
'
@chakra-ui/react
'
;
import
{
createListCollection
,
Flex
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
MouseEvent
}
from
'
react
'
;
import
type
{
MouseEvent
}
from
'
react
'
;
import
type
{
TabItemRegular
}
from
'
toolkit/components/AdaptiveTabs/types
'
;
import
{
MarketplaceCategory
}
from
'
types/client/marketplace
'
;
import
{
MarketplaceCategory
}
from
'
types/client/marketplace
'
;
import
type
{
TabItem
}
from
'
ui/shared/Tabs/types
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
throwOnResourceLoadError
from
'
lib/errors/throwOnResourceLoadError
'
;
import
throwOnResourceLoadError
from
'
lib/errors/throwOnResourceLoadError
'
;
import
useGraphLinks
from
'
lib/hooks/useGraphLinks
'
;
import
useGraphLinks
from
'
lib/hooks/useGraphLinks
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
{
IconButton
}
from
'
toolkit/chakra/icon-button
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
MenuContent
,
MenuItem
,
MenuRoot
,
MenuTrigger
}
from
'
toolkit/chakra/menu
'
;
import
AdaptiveTabs
from
'
toolkit/components/AdaptiveTabs/AdaptiveTabs
'
;
import
Banner
from
'
ui/marketplace/Banner
'
;
import
Banner
from
'
ui/marketplace/Banner
'
;
import
ContractListModal
from
'
ui/marketplace/ContractListModal
'
;
import
ContractListModal
from
'
ui/marketplace/ContractListModal
'
;
import
MarketplaceAppModal
from
'
ui/marketplace/MarketplaceAppModal
'
;
import
MarketplaceAppModal
from
'
ui/marketplace/MarketplaceAppModal
'
;
import
MarketplaceDisclaimerModal
from
'
ui/marketplace/MarketplaceDisclaimerModal
'
;
import
MarketplaceDisclaimerModal
from
'
ui/marketplace/MarketplaceDisclaimerModal
'
;
import
MarketplaceList
from
'
ui/marketplace/MarketplaceList
'
;
import
MarketplaceList
from
'
ui/marketplace/MarketplaceList
'
;
import
type
{
SortValue
}
from
'
ui/marketplace/utils
'
;
import
{
SORT_OPTIONS
}
from
'
ui/marketplace/utils
'
;
import
{
SORT_OPTIONS
}
from
'
ui/marketplace/utils
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
ActionBar
from
'
ui/shared/ActionBar
'
;
import
Menu
from
'
ui/shared/chakra/Menu
'
;
import
FilterInput
from
'
ui/shared/filters/FilterInput
'
;
import
FilterInput
from
'
ui/shared/filters/FilterInput
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
type
{
IconName
}
from
'
ui/shared/IconSvg
'
;
import
type
{
IconName
}
from
'
ui/shared/IconSvg
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
import
Sort
from
'
ui/shared/sort/Sort
'
;
import
Sort
from
'
ui/shared/sort/Sort
'
;
import
TabsWithScroll
from
'
ui/shared/Tabs/TabsWithScroll
'
;
import
useMarketplace
from
'
../marketplace/useMarketplace
'
;
import
useMarketplace
from
'
../marketplace/useMarketplace
'
;
const
sortCollection
=
createListCollection
({
items
:
SORT_OPTIONS
});
const
feature
=
config
.
features
.
marketplace
;
const
feature
=
config
.
features
.
marketplace
;
const
links
:
Array
<
{
label
:
string
;
href
:
string
;
icon
:
IconName
}
>
=
[];
const
links
:
Array
<
{
label
:
string
;
href
:
string
;
icon
:
IconName
}
>
=
[];
...
@@ -84,7 +89,7 @@ const Marketplace = () => {
...
@@ -84,7 +89,7 @@ const Marketplace = () => {
const
graphLinksQuery
=
useGraphLinks
();
const
graphLinksQuery
=
useGraphLinks
();
const
categoryTabs
=
React
.
useMemo
(()
=>
{
const
categoryTabs
=
React
.
useMemo
(()
=>
{
const
tabs
:
Array
<
TabItem
>
=
categories
.
map
(
category
=>
({
const
tabs
:
Array
<
TabItem
Regular
>
=
categories
.
map
(
category
=>
({
id
:
category
.
name
,
id
:
category
.
name
,
title
:
category
.
name
,
title
:
category
.
name
,
count
:
category
.
count
,
count
:
category
.
count
,
...
@@ -108,15 +113,15 @@ const Marketplace = () => {
...
@@ -108,15 +113,15 @@ const Marketplace = () => {
return
tabs
;
return
tabs
;
},
[
categories
,
appsTotal
,
favoriteApps
.
length
]);
},
[
categories
,
appsTotal
,
favoriteApps
.
length
]);
const
selected
CategoryIndex
=
React
.
useMemo
(()
=>
{
const
selected
TabId
=
React
.
useMemo
(()
=>
{
const
index
=
categoryTabs
.
findIndex
(
c
=>
c
.
id
===
selectedCategoryId
);
const
tab
=
categoryTabs
.
find
(
c
=>
c
.
id
===
selectedCategoryId
);
return
index
===
-
1
?
0
:
index
;
return
typeof
tab
?.
id
===
'
string
'
?
tab
.
id
:
undefined
;
},
[
categoryTabs
,
selectedCategoryId
]);
},
[
categoryTabs
,
selectedCategoryId
]);
const
selectedApp
=
displayedApps
.
find
(
app
=>
app
.
id
===
selectedAppId
);
const
selectedApp
=
displayedApps
.
find
(
app
=>
app
.
id
===
selectedAppId
);
const
handleCategoryChange
=
React
.
useCallback
((
index
:
number
)
=>
{
const
handleCategoryChange
=
React
.
useCallback
((
{
value
}:
{
value
:
string
}
)
=>
{
const
tabId
=
categoryTabs
[
index
]
.
id
;
const
tabId
=
categoryTabs
.
find
(
c
=>
c
.
id
===
value
)?
.
id
;
if
(
typeof
tabId
===
'
string
'
)
{
if
(
typeof
tabId
===
'
string
'
)
{
onCategoryChange
(
tabId
);
onCategoryChange
(
tabId
);
}
}
...
@@ -137,6 +142,10 @@ const Marketplace = () => {
...
@@ -137,6 +142,10 @@ const Marketplace = () => {
}
}
},
[
clearSelectedAppId
,
showAppInfo
,
selectedApp
]);
},
[
clearSelectedAppId
,
showAppInfo
,
selectedApp
]);
const
handleSortChange
=
React
.
useCallback
(({
value
}:
{
value
:
Array
<
string
>
})
=>
{
setSorting
(
value
[
0
]
as
SortValue
);
},
[
setSorting
]);
throwOnResourceLoadError
(
isError
&&
error
?
{
isError
,
error
}
:
{
isError
:
false
,
error
:
null
});
throwOnResourceLoadError
(
isError
&&
error
?
{
isError
,
error
}
:
{
isError
:
false
,
error
:
null
});
if
(
!
feature
.
isEnabled
)
{
if
(
!
feature
.
isEnabled
)
{
...
@@ -151,32 +160,34 @@ const Marketplace = () => {
...
@@ -151,32 +160,34 @@ const Marketplace = () => {
title=
"DAppscout"
title=
"DAppscout"
mb=
{
2
}
mb=
{
2
}
contentAfter=
{
(
isMobile
&&
links
.
length
>
1
)
?
(
contentAfter=
{
(
isMobile
&&
links
.
length
>
1
)
?
(
<
Menu
>
<
MenuRoot
>
<
MenuButton
<
MenuTrigger
asChild
>
as=
{
IconButton
}
<
IconButton
size=
"sm"
variant=
"dropdown"
variant=
"outline"
size=
"sm"
colorScheme=
"gray"
px=
"9px"
px=
"9px"
ml=
"auto"
ml=
"auto"
>
icon=
{
<
IconSvg
name=
"dots"
boxSize=
"18px"
/>
}
<
IconSvg
name=
"dots"
boxSize=
"18px"
/>
/>
</
IconButton
>
<
MenuList
minW=
"max-content"
>
</
MenuTrigger
>
<
MenuContent
>
{
links
.
map
(({
label
,
href
,
icon
})
=>
(
{
links
.
map
(({
label
,
href
,
icon
})
=>
(
<
MenuItem
key=
{
label
}
as=
"a"
href=
{
href
}
target=
"_blank"
py=
{
2
}
px=
{
4
}
>
<
MenuItem
key=
{
label
}
value=
{
label
}
asChild
>
<
IconSvg
name=
{
icon
}
boxSize=
{
4
}
mr=
{
2.5
}
/>
<
Link
external
href=
{
href
}
variant=
"menu"
gap=
{
0
}
>
{
label
}
<
IconSvg
name=
{
icon
}
boxSize=
{
4
}
mr=
{
2
}
/>
<
IconSvg
name=
"link_external"
boxSize=
{
3
}
color=
"icon_link_external"
ml=
{
2
}
/>
{
label
}
</
Link
>
</
MenuItem
>
</
MenuItem
>
))
}
))
}
</
Menu
Lis
t
>
</
Menu
Conten
t
>
</
Menu
>
</
Menu
Root
>
)
:
(
)
:
(
<
Flex
ml=
"auto"
>
<
Flex
ml=
"auto"
>
{
links
.
map
(({
label
,
href
})
=>
(
{
links
.
map
(({
label
,
href
})
=>
(
<
Link
External
key=
{
label
}
href=
{
href
}
variant=
"subtle"
fontSize=
"sm"
lineHeight=
{
5
}
ml=
{
2
}
>
<
Link
external
key=
{
label
}
href=
{
href
}
variant=
"underlaid"
textStyle=
"sm"
ml=
{
2
}
>
{
label
}
{
label
}
</
Link
External
>
</
Link
>
))
}
))
}
</
Flex
>
</
Flex
>
)
}
)
}
...
@@ -200,10 +211,10 @@ const Marketplace = () => {
...
@@ -200,10 +211,10 @@ const Marketplace = () => {
pt=
{
{
base
:
4
,
lg
:
6
}
}
pt=
{
{
base
:
4
,
lg
:
6
}
}
pb=
{
{
base
:
4
,
lg
:
3
}
}
pb=
{
{
base
:
4
,
lg
:
3
}
}
>
>
<
TabsWithScroll
<
AdaptiveTabs
tabs=
{
categoryTabs
}
tabs=
{
categoryTabs
}
on
Tab
Change=
{
handleCategoryChange
}
on
Value
Change=
{
handleCategoryChange
}
default
TabIndex=
{
selectedCategoryIndex
}
default
Value=
{
selectedTabId
}
marginBottom=
{
-
2
}
marginBottom=
{
-
2
}
isLoading=
{
isCategoriesPlaceholderData
}
isLoading=
{
isCategoriesPlaceholderData
}
/>
/>
...
@@ -212,8 +223,9 @@ const Marketplace = () => {
...
@@ -212,8 +223,9 @@ const Marketplace = () => {
{
showSort
&&
(
{
showSort
&&
(
<
Sort
<
Sort
name=
"dapps_sorting"
name=
"dapps_sorting"
options=
{
SORT_OPTIONS
}
collection=
{
sortCollection
}
onChange=
{
setSorting
}
onValueChange=
{
handleSortChange
}
defaultValue=
{
[
sortCollection
.
items
[
0
].
value
]
}
isLoading=
{
isPlaceholderData
}
isLoading=
{
isPlaceholderData
}
/>
/>
)
}
)
}
...
@@ -221,8 +233,8 @@ const Marketplace = () => {
...
@@ -221,8 +233,8 @@ const Marketplace = () => {
initialValue=
{
filterQuery
}
initialValue=
{
filterQuery
}
onChange=
{
onSearchInputChange
}
onChange=
{
onSearchInputChange
}
placeholder=
"Find app by name or keyword..."
placeholder=
"Find app by name or keyword..."
isL
oading=
{
isPlaceholderData
}
l
oading=
{
isPlaceholderData
}
size=
{
showSort
?
'
xs
'
:
'
sm
'
}
size=
"sm"
w=
{
{
base
:
'
100%
'
,
lg
:
'
350px
'
}
}
w=
{
{
base
:
'
100%
'
,
lg
:
'
350px
'
}
}
/>
/>
</
Flex
>
</
Flex
>
...
...
ui/shared/chakra/PinInput.tsx
deleted
100644 → 0
View file @
4aaf1f1a
import
type
{
PinInputProps
,
StyleProps
}
from
'
@chakra-ui/react
'
;
// eslint-disable-next-line no-restricted-imports
import
{
PinInput
as
PinInputBase
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
const
PinInput
=
(
props
:
PinInputProps
&
{
bgColor
?:
StyleProps
[
'
bgColor
'
]
})
=>
{
return
<
PinInputBase
{
...
props
}
/>;
};
export
default
React
.
memo
(
PinInput
);
ui/shared/chakra/Popover.tsx
deleted
100644 → 0
View file @
4aaf1f1a
import
type
{
PopoverProps
}
from
'
@chakra-ui/react
'
;
// eslint-disable-next-line no-restricted-imports
import
{
Popover
as
PopoverBase
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
const
Popover
=
(
props
:
PopoverProps
)
=>
{
return
<
PopoverBase
gutter=
{
4
}
{
...
props
}
/>;
};
export
default
React
.
memo
(
Popover
);
ui/shared/chakra/Tag.tsx
deleted
100644 → 0
View file @
4aaf1f1a
import
{
Tag
as
ChakraTag
}
from
'
@chakra-ui/react
'
;
import
type
{
TagProps
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
TruncatedTextTooltip
from
'
ui/shared/TruncatedTextTooltip
'
;
export
interface
Props
extends
TagProps
{
isLoading
?:
boolean
;
}
const
Tag
=
({
isLoading
,
...
props
}:
Props
,
ref
:
React
.
ForwardedRef
<
HTMLDivElement
>
)
=>
{
if
(
props
.
isTruncated
&&
typeof
props
.
children
===
'
string
'
)
{
if
(
!
props
.
children
)
{
return
null
;
}
return
(
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
borderRadius=
"sm"
maxW=
"100%"
>
<
TruncatedTextTooltip
label=
{
props
.
children
}
>
<
ChakraTag
{
...
props
}
ref=
{
ref
}
/>
</
TruncatedTextTooltip
>
</
Skeleton
>
);
}
return
(
<
Skeleton
isLoaded=
{
!
isLoading
}
display=
"inline-block"
borderRadius=
"sm"
maxW=
"100%"
>
<
ChakraTag
{
...
props
}
ref=
{
ref
}
/>
</
Skeleton
>
);
};
export
default
React
.
memo
(
React
.
forwardRef
(
Tag
));
ui/shared/solidityscanReport/SolidityscanReportButton.tsx
View file @
6aba61a4
import
{
Spinner
}
from
'
@chakra-ui/react
'
;
import
type
{
BoxProps
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Spinner
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
usePreventFocusAfterModalClosing
from
'
lib/hooks/usePreventFocusAfterModalClosing
'
;
import
usePreventFocusAfterModalClosing
from
'
lib/hooks/usePreventFocusAfterModalClosing
'
;
...
@@ -15,10 +16,11 @@ interface Props extends ButtonProps {
...
@@ -15,10 +16,11 @@ interface Props extends ButtonProps {
isLoading
?:
boolean
;
isLoading
?:
boolean
;
onlyIcon
?:
boolean
;
onlyIcon
?:
boolean
;
label
?:
string
|
React
.
ReactElement
;
label
?:
string
|
React
.
ReactElement
;
wrapperProps
?:
BoxProps
;
}
}
const
SolidityscanReportButton
=
(
const
SolidityscanReportButton
=
(
{
score
,
isLoading
,
onlyIcon
,
label
=
'
Security score
'
,
...
rest
}:
Props
,
{
score
,
isLoading
,
onlyIcon
,
label
=
'
Security score
'
,
wrapperProps
,
...
rest
}:
Props
,
)
=>
{
)
=>
{
const
{
scoreColor
}
=
useScoreLevelAndColor
(
score
);
const
{
scoreColor
}
=
useScoreLevelAndColor
(
score
);
const
colorLoading
=
{
_light
:
'
gray.300
'
,
_dark
:
'
gray.600
'
};
const
colorLoading
=
{
_light
:
'
gray.300
'
,
_dark
:
'
gray.600
'
};
...
@@ -26,7 +28,7 @@ const SolidityscanReportButton = (
...
@@ -26,7 +28,7 @@ const SolidityscanReportButton = (
return
(
return
(
<
Tooltip
content=
{
label
}
disableOnMobile
>
<
Tooltip
content=
{
label
}
disableOnMobile
>
<
div
>
<
Box
{
...
wrapperProps
}
>
<
PopoverTrigger
>
<
PopoverTrigger
>
<
Button
<
Button
color=
{
isLoading
?
colorLoading
:
scoreColor
}
color=
{
isLoading
?
colorLoading
:
scoreColor
}
...
@@ -52,7 +54,7 @@ const SolidityscanReportButton = (
...
@@ -52,7 +54,7 @@ const SolidityscanReportButton = (
{
!
isLoading
&&
(
onlyIcon
?
null
:
score
)
}
{
!
isLoading
&&
(
onlyIcon
?
null
:
score
)
}
</
Button
>
</
Button
>
</
PopoverTrigger
>
</
PopoverTrigger
>
</
div
>
</
Box
>
</
Tooltip
>
</
Tooltip
>
);
);
};
};
...
...
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