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
27872bfe
Commit
27872bfe
authored
Feb 13, 2025
by
tom
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
contract details tab
parent
4a55cf1a
Changes
35
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
517 additions
and
388 deletions
+517
-388
accordion.tsx
toolkit/chakra/accordion.tsx
+4
-3
alert.tsx
toolkit/chakra/alert.tsx
+4
-1
tabs.tsx
toolkit/chakra/tabs.tsx
+3
-1
AdaptiveTabsMenu.tsx
toolkit/components/AdaptiveTabs/AdaptiveTabsMenu.tsx
+2
-0
semanticTokens.ts
toolkit/theme/foundations/semanticTokens.ts
+9
-0
accordion.recipe.ts
toolkit/theme/recipes/accordion.recipe.ts
+15
-0
tabs.recipe.ts
toolkit/theme/recipes/tabs.recipe.ts
+33
-0
AddressContract.tsx
ui/address/AddressContract.tsx
+4
-4
ContractCodeIdes.tsx
ui/address/contract/ContractCodeIdes.tsx
+18
-27
ContractDetails.tsx
ui/address/contract/ContractDetails.tsx
+3
-3
ContractSourceCode.tsx
ui/address/contract/ContractSourceCode.tsx
+13
-12
ContractDetailsAlertProxyPattern.tsx
...ress/contract/alerts/ContractDetailsAlertProxyPattern.tsx
+4
-4
ContractDetailsAlertVerificationSource.tsx
...ontract/alerts/ContractDetailsAlertVerificationSource.tsx
+9
-8
ContractDetailsAlerts.tsx
ui/address/contract/alerts/ContractDetailsAlerts.tsx
+11
-11
ContractSecurityAudits.tsx
ui/address/contract/audits/ContractSecurityAudits.tsx
+8
-6
ContractSubmitAuditForm.tsx
ui/address/contract/audits/ContractSubmitAuditForm.tsx
+16
-25
ContractDetailsInfo.tsx
ui/address/contract/info/ContractDetailsInfo.tsx
+41
-29
ContractDetailsInfoItem.tsx
ui/address/contract/info/ContractDetailsInfoItem.tsx
+8
-9
useContractDetailsTabs.tsx
ui/address/contract/useContractDetailsTabs.tsx
+2
-1
useContractTabs.tsx
ui/address/contract/useContractTabs.tsx
+6
-6
Address.tsx
ui/pages/Address.tsx
+23
-23
CodeViewSnippet.tsx
ui/shared/CodeViewSnippet.tsx
+3
-3
CoinzillaTextAd.tsx
ui/shared/ad/CoinzillaTextAd.tsx
+1
-1
FormFieldText.tsx
ui/shared/forms/fields/FormFieldText.tsx
+4
-3
types.ts
ui/shared/forms/fields/types.ts
+3
-2
CodeEditor.tsx
ui/shared/monaco/CodeEditor.tsx
+21
-20
CodeEditorFileTree.tsx
ui/shared/monaco/CodeEditorFileTree.tsx
+52
-39
CodeEditorMainFileIndicator.tsx
ui/shared/monaco/CodeEditorMainFileIndicator.tsx
+3
-2
CodeEditorSearch.tsx
ui/shared/monaco/CodeEditorSearch.tsx
+73
-50
CodeEditorSearchSection.tsx
ui/shared/monaco/CodeEditorSearchSection.tsx
+56
-53
CodeEditorSideBar.tsx
ui/shared/monaco/CodeEditorSideBar.tsx
+47
-38
CodeEditorTab.tsx
ui/shared/monaco/CodeEditorTab.tsx
+1
-1
themes.ts
ui/shared/monaco/utils/themes.ts
+4
-2
useThemeColors.ts
ui/shared/monaco/utils/useThemeColors.ts
+1
-1
Tabs.tsx
ui/showcases/Tabs.tsx
+12
-0
No files found.
toolkit/chakra/accordion.tsx
View file @
27872bfe
...
@@ -5,6 +5,7 @@ import IconSvg from 'ui/shared/IconSvg';
...
@@ -5,6 +5,7 @@ import IconSvg from 'ui/shared/IconSvg';
interface
AccordionItemTriggerProps
extends
Accordion
.
ItemTriggerProps
{
interface
AccordionItemTriggerProps
extends
Accordion
.
ItemTriggerProps
{
indicatorPlacement
?:
'
start
'
|
'
end
'
;
indicatorPlacement
?:
'
start
'
|
'
end
'
;
noIndicator
?:
boolean
;
variant
?:
Accordion
.
RootProps
[
'
variant
'
];
variant
?:
Accordion
.
RootProps
[
'
variant
'
];
}
}
...
@@ -12,7 +13,7 @@ export const AccordionItemTrigger = React.forwardRef<
...
@@ -12,7 +13,7 @@ export const AccordionItemTrigger = React.forwardRef<
HTMLButtonElement
,
HTMLButtonElement
,
AccordionItemTriggerProps
AccordionItemTriggerProps
>
(
function
AccordionItemTrigger
(
props
,
ref
)
{
>
(
function
AccordionItemTrigger
(
props
,
ref
)
{
const
{
children
,
indicatorPlacement
:
indicatorPlacementProp
,
variant
,
...
rest
}
=
props
;
const
{
children
,
indicatorPlacement
:
indicatorPlacementProp
,
variant
,
noIndicator
,
...
rest
}
=
props
;
const
indicatorPlacement
=
variant
===
'
faq
'
?
'
start
'
:
(
indicatorPlacementProp
??
'
end
'
);
const
indicatorPlacement
=
variant
===
'
faq
'
?
'
start
'
:
(
indicatorPlacementProp
??
'
end
'
);
...
@@ -59,9 +60,9 @@ export const AccordionItemTrigger = React.forwardRef<
...
@@ -59,9 +60,9 @@ export const AccordionItemTrigger = React.forwardRef<
return
(
return
(
<
Accordion
.
ItemTrigger
className=
"group"
{
...
rest
}
ref=
{
ref
}
>
<
Accordion
.
ItemTrigger
className=
"group"
{
...
rest
}
ref=
{
ref
}
>
{
indicatorPlacement
===
'
start
'
&&
indicator
}
{
indicatorPlacement
===
'
start
'
&&
!
noIndicator
&&
indicator
}
{
children
}
{
children
}
{
indicatorPlacement
===
'
end
'
&&
indicator
}
{
indicatorPlacement
===
'
end
'
&&
!
noIndicator
&&
indicator
}
</
Accordion
.
ItemTrigger
>
</
Accordion
.
ItemTrigger
>
);
);
});
});
...
...
toolkit/chakra/alert.tsx
View file @
27872bfe
import
type
{
AlertDescriptionProps
}
from
'
@chakra-ui/react
'
;
import
{
Alert
as
ChakraAlert
}
from
'
@chakra-ui/react
'
;
import
{
Alert
as
ChakraAlert
}
from
'
@chakra-ui/react
'
;
import
*
as
React
from
'
react
'
;
import
*
as
React
from
'
react
'
;
...
@@ -9,6 +10,7 @@ import { Skeleton } from './skeleton';
...
@@ -9,6 +10,7 @@ import { Skeleton } from './skeleton';
export
interface
AlertProps
extends
Omit
<
ChakraAlert
.
RootProps
,
'
title
'
>
{
export
interface
AlertProps
extends
Omit
<
ChakraAlert
.
RootProps
,
'
title
'
>
{
startElement
?:
React
.
ReactNode
;
startElement
?:
React
.
ReactNode
;
endElement
?:
React
.
ReactNode
;
endElement
?:
React
.
ReactNode
;
descriptionProps
?:
AlertDescriptionProps
;
title
?:
React
.
ReactNode
;
title
?:
React
.
ReactNode
;
icon
?:
React
.
ReactElement
;
icon
?:
React
.
ReactElement
;
closable
?:
boolean
;
closable
?:
boolean
;
...
@@ -29,6 +31,7 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
...
@@ -29,6 +31,7 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
endElement
,
endElement
,
loading
,
loading
,
showIcon
=
false
,
showIcon
=
false
,
descriptionProps
,
...
rest
...
rest
}
=
props
;
}
=
props
;
...
@@ -53,7 +56,7 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
...
@@ -53,7 +56,7 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
{
children
?
(
{
children
?
(
<
ChakraAlert
.
Content
>
<
ChakraAlert
.
Content
>
{
title
&&
<
ChakraAlert
.
Title
>
{
title
}
</
ChakraAlert
.
Title
>
}
{
title
&&
<
ChakraAlert
.
Title
>
{
title
}
</
ChakraAlert
.
Title
>
}
<
ChakraAlert
.
Description
display=
"inline-flex"
>
{
children
}
</
ChakraAlert
.
Description
>
<
ChakraAlert
.
Description
display=
"inline-flex"
flexWrap=
"wrap"
{
...
descriptionProps
}
>
{
children
}
</
ChakraAlert
.
Description
>
</
ChakraAlert
.
Content
>
</
ChakraAlert
.
Content
>
)
:
(
)
:
(
<
ChakraAlert
.
Title
flex=
"1"
>
{
title
}
</
ChakraAlert
.
Title
>
<
ChakraAlert
.
Title
flex=
"1"
>
{
title
}
</
ChakraAlert
.
Title
>
...
...
toolkit/chakra/tabs.tsx
View file @
27872bfe
...
@@ -12,7 +12,9 @@ export const TabsRoot = React.forwardRef<HTMLDivElement, TabsProps>(
...
@@ -12,7 +12,9 @@ export const TabsRoot = React.forwardRef<HTMLDivElement, TabsProps>(
export
const
TabsList
=
ChakraTabs
.
List
;
export
const
TabsList
=
ChakraTabs
.
List
;
export
const
TabsTrigger
=
React
.
forwardRef
<
HTMLButtonElement
,
ChakraTabs
.
TriggerProps
>
(
export
interface
TabsTriggerProps
extends
ChakraTabs
.
TriggerProps
{}
export
const
TabsTrigger
=
React
.
forwardRef
<
HTMLButtonElement
,
TabsTriggerProps
>
(
function
TabsTrigger
(
props
,
ref
)
{
function
TabsTrigger
(
props
,
ref
)
{
return
<
ChakraTabs
.
Trigger
ref=
{
ref
}
className=
"group"
{
...
props
}
/>;
return
<
ChakraTabs
.
Trigger
ref=
{
ref
}
className=
"group"
{
...
props
}
/>;
},
},
...
...
toolkit/components/AdaptiveTabs/AdaptiveTabsMenu.tsx
View file @
27872bfe
...
@@ -21,6 +21,8 @@ const AdaptiveTabsMenu = ({ tabs, tabsCut, isActive, ...props }: Props, ref: Rea
...
@@ -21,6 +21,8 @@ const AdaptiveTabsMenu = ({ tabs, tabsCut, isActive, ...props }: Props, ref: Rea
<
PopoverRoot
positioning=
{
{
placement
:
'
bottom-end
'
}
}
>
<
PopoverRoot
positioning=
{
{
placement
:
'
bottom-end
'
}
}
>
<
PopoverTrigger
>
<
PopoverTrigger
>
<
Button
<
Button
// we use "div" so the :last-of-type pseudo-class targets the last tab and not the menu trigger
as=
"div"
variant=
"plain"
variant=
"plain"
color=
"tabs.solid.fg"
color=
"tabs.solid.fg"
_hover=
{
{
_hover=
{
{
...
...
toolkit/theme/foundations/semanticTokens.ts
View file @
27872bfe
...
@@ -175,6 +175,15 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
...
@@ -175,6 +175,15 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
DEFAULT
:
{
value
:
{
_light
:
'
{colors.gray.200}
'
,
_dark
:
'
{colors.gray.600}
'
}
},
DEFAULT
:
{
value
:
{
_light
:
'
{colors.gray.200}
'
,
_dark
:
'
{colors.gray.600}
'
}
},
},
},
},
},
segmented
:
{
fg
:
{
DEFAULT
:
{
value
:
{
_light
:
'
{colors.blue.600}
'
,
_dark
:
'
{colors.blue.300}
'
}
},
selected
:
{
value
:
{
_light
:
'
{colors.blue.700}
'
,
_dark
:
'
{colors.gray.50}
'
}
},
},
border
:
{
DEFAULT
:
{
value
:
{
_light
:
'
{colors.blue.50}
'
,
_dark
:
'
{colors.gray.800}
'
}
},
},
},
},
},
'
switch
'
:
{
'
switch
'
:
{
primary
:
{
primary
:
{
...
...
toolkit/theme/recipes/accordion.recipe.ts
View file @
27872bfe
...
@@ -49,6 +49,21 @@ export const recipe = defineSlotRecipe({
...
@@ -49,6 +49,21 @@ export const recipe = defineSlotRecipe({
},
},
variants
:
{
variants
:
{
noAnimation
:
{
'
true
'
:
{
itemContent
:
{
_open
:
{
animationName
:
'
none
'
,
},
_closed
:
{
animationName
:
'
none
'
,
},
},
itemIndicator
:
{
transition
:
'
none
'
,
},
},
},
variant
:
{
variant
:
{
outline
:
{
outline
:
{
item
:
{
item
:
{
...
...
toolkit/theme/recipes/tabs.recipe.ts
View file @
27872bfe
...
@@ -124,6 +124,7 @@ export const recipe = defineSlotRecipe({
...
@@ -124,6 +124,7 @@ export const recipe = defineSlotRecipe({
textStyle
:
'
md
'
,
textStyle
:
'
md
'
,
},
},
},
},
free
:
{},
},
},
variant
:
{
variant
:
{
...
@@ -178,6 +179,38 @@ export const recipe = defineSlotRecipe({
...
@@ -178,6 +179,38 @@ export const recipe = defineSlotRecipe({
},
},
},
},
},
},
segmented
:
{
trigger
:
{
color
:
'
tabs.segmented.fg
'
,
bg
:
'
transparent
'
,
borderWidth
:
'
2px
'
,
borderStyle
:
'
solid
'
,
borderColor
:
'
tabs.segmented.border
'
,
_hover
:
{
color
:
'
link.primary.hover
'
,
},
_selected
:
{
color
:
'
tabs.segmented.fg.selected
'
,
bg
:
'
tabs.segmented.border
'
,
borderColor
:
'
tabs.segmented.border
'
,
_hover
:
{
color
:
'
tabs.segmented.fg.selected
'
,
},
},
_notFirst
:
{
borderLeftWidth
:
'
0
'
,
},
_first
:
{
borderTopLeftRadius
:
'
base
'
,
borderBottomLeftRadius
:
'
base
'
,
},
_last
:
{
borderTopRightRadius
:
'
base
'
,
borderBottomRightRadius
:
'
base
'
,
},
},
},
unstyled
:
{},
},
},
},
},
...
...
ui/address/AddressContract.tsx
View file @
27872bfe
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
RoutedSubTab
}
from
'
ui/shared/
Tabs/types
'
;
import
type
{
TabItemRegular
}
from
'
toolkit/components/Adaptive
Tabs/types
'
;
import
RoutedTabs
from
'
ui/shared/
Tabs/RoutedTabs
'
;
import
RoutedTabs
from
'
toolkit/components/Routed
Tabs/RoutedTabs
'
;
interface
Props
{
interface
Props
{
tabs
:
Array
<
RoutedSubTab
>
;
tabs
:
Array
<
TabItemRegular
>
;
isLoading
:
boolean
;
isLoading
:
boolean
;
shouldRender
?:
boolean
;
shouldRender
?:
boolean
;
}
}
...
@@ -20,7 +20,7 @@ const AddressContract = ({ tabs, isLoading, shouldRender }: Props) => {
...
@@ -20,7 +20,7 @@ const AddressContract = ({ tabs, isLoading, shouldRender }: Props) => {
}
}
return
(
return
(
<
RoutedTabs
tabs=
{
tabs
}
variant=
"outline"
colorScheme=
"gray"
size=
"sm"
tabL
istProps=
{
TAB_LIST_PROPS
}
isLoading=
{
isLoading
}
/>
<
RoutedTabs
tabs=
{
tabs
}
variant=
"outline"
colorScheme=
"gray"
size=
"sm"
l
istProps=
{
TAB_LIST_PROPS
}
isLoading=
{
isLoading
}
/>
);
);
};
};
...
...
ui/address/contract/ContractCodeIdes.tsx
View file @
27872bfe
import
{
import
{
Flex
,
chakra
}
from
'
@chakra-ui/react
'
;
Flex
,
Button
,
chakra
,
PopoverTrigger
,
PopoverBody
,
PopoverContent
,
Image
,
useDisclosure
,
useColorModeValue
,
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
Popover
from
'
ui/shared/chakra/Popover
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
useColorModeValue
}
from
'
toolkit/chakra/color-mode
'
;
import
{
Image
}
from
'
toolkit/chakra/image
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
PopoverRoot
,
PopoverTrigger
,
PopoverContent
,
PopoverBody
}
from
'
toolkit/chakra/popover
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
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
;
hash
:
string
;
hash
:
string
;
isLoading
?:
string
;
isLoading
?:
boolean
;
}
}
const
ContractCodeIde
=
({
className
,
hash
,
isLoading
}:
Props
)
=>
{
const
ContractCodeIde
=
({
className
,
hash
,
isLoading
}:
Props
)
=>
{
const
{
isOpen
,
onToggle
,
onClos
e
}
=
useDisclosure
();
const
{
open
,
onOpenChang
e
}
=
useDisclosure
();
const
defaultIconColor
=
useColorModeValue
(
'
gray.600
'
,
'
gray.500
'
);
const
defaultIconColor
=
useColorModeValue
(
'
gray.600
'
,
'
gray.500
'
);
const
ideLinks
=
React
.
useMemo
(()
=>
{
const
ideLinks
=
React
.
useMemo
(()
=>
{
...
@@ -36,16 +30,16 @@ const ContractCodeIde = ({ className, hash, isLoading }: Props) => {
...
@@ -36,16 +30,16 @@ const ContractCodeIde = ({ className, hash, isLoading }: Props) => {
<
IconSvg
name=
"ABI_slim"
boxSize=
{
5
}
color=
{
defaultIconColor
}
mr=
{
2
}
/>;
<
IconSvg
name=
"ABI_slim"
boxSize=
{
5
}
color=
{
defaultIconColor
}
mr=
{
2
}
/>;
return
(
return
(
<
Link
E
xternal
key=
{
ide
.
title
}
href=
{
url
}
display=
"inline-flex"
alignItems=
"center"
>
<
Link
e
xternal
key=
{
ide
.
title
}
href=
{
url
}
display=
"inline-flex"
alignItems=
"center"
>
{
icon
}
{
icon
}
{
ide
.
title
}
{
ide
.
title
}
</
Link
External
>
</
Link
>
);
);
});
});
},
[
defaultIconColor
,
hash
]);
},
[
defaultIconColor
,
hash
]);
if
(
isLoading
)
{
if
(
isLoading
)
{
return
<
Skeleton
h=
{
8
}
w=
"92px"
borderRadius=
"base"
/>;
return
<
Skeleton
loading
h=
{
8
}
w=
"92px"
borderRadius=
"base"
/>;
}
}
if
(
ideLinks
.
length
===
0
)
{
if
(
ideLinks
.
length
===
0
)
{
...
@@ -53,23 +47,20 @@ const ContractCodeIde = ({ className, hash, isLoading }: Props) => {
...
@@ -53,23 +47,20 @@ const ContractCodeIde = ({ className, hash, isLoading }: Props) => {
}
}
return
(
return
(
<
Popover
isOpen=
{
isOpen
}
onClose=
{
onClose
}
placement=
"bottom-start"
isLazy
>
<
Popover
Root
open=
{
open
}
onOpenChange=
{
onOpenChange
}
>
<
PopoverTrigger
>
<
PopoverTrigger
>
<
Button
<
Button
className=
{
className
}
className=
{
className
}
size=
"sm"
size=
"sm"
variant=
"outline"
variant=
"dropdown"
colorScheme=
"gray"
onClick=
{
onToggle
}
isActive=
{
isOpen
}
aria
-
label=
"Open source code in IDE"
aria
-
label=
"Open source code in IDE"
fontWeight=
{
500
}
fontWeight=
{
500
}
px=
{
2
}
gap=
{
0
}
h=
"32px"
h=
"32px"
flexShrink=
{
0
}
flexShrink=
{
0
}
>
>
<
span
>
Open in
</
span
>
<
span
>
Open in
</
span
>
<
IconSvg
name=
"arrows/east-mini"
transform=
{
isO
pen
?
'
rotate(90deg)
'
:
'
rotate(-90deg)
'
}
transitionDuration=
"faster"
boxSize=
{
5
}
/>
<
IconSvg
name=
"arrows/east-mini"
transform=
{
o
pen
?
'
rotate(90deg)
'
:
'
rotate(-90deg)
'
}
transitionDuration=
"faster"
boxSize=
{
5
}
/>
</
Button
>
</
Button
>
</
PopoverTrigger
>
</
PopoverTrigger
>
<
PopoverContent
w=
"240px"
>
<
PopoverContent
w=
"240px"
>
...
@@ -86,7 +77,7 @@ const ContractCodeIde = ({ className, hash, isLoading }: Props) => {
...
@@ -86,7 +77,7 @@ const ContractCodeIde = ({ className, hash, isLoading }: Props) => {
</
Flex
>
</
Flex
>
</
PopoverBody
>
</
PopoverBody
>
</
PopoverContent
>
</
PopoverContent
>
</
Popover
>
</
Popover
Root
>
);
);
};
};
...
...
ui/address/contract/ContractDetails.tsx
View file @
27872bfe
...
@@ -15,8 +15,8 @@ import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
...
@@ -15,8 +15,8 @@ import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
import
getQueryParamString
from
'
lib/router/getQueryParamString
'
;
import
getQueryParamString
from
'
lib/router/getQueryParamString
'
;
import
useSocketMessage
from
'
lib/socket/useSocketMessage
'
;
import
useSocketMessage
from
'
lib/socket/useSocketMessage
'
;
import
*
as
stubs
from
'
stubs/contract
'
;
import
*
as
stubs
from
'
stubs/contract
'
;
import
RoutedTabs
from
'
toolkit/components/RoutedTabs/RoutedTabs
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
DataFetchAlert
from
'
ui/shared/DataFetchAlert
'
;
import
RoutedTabs
from
'
ui/shared/Tabs/RoutedTabs
'
;
import
ContractDetailsAlerts
from
'
./alerts/ContractDetailsAlerts
'
;
import
ContractDetailsAlerts
from
'
./alerts/ContractDetailsAlerts
'
;
import
ContractSourceAddressSelector
from
'
./ContractSourceAddressSelector
'
;
import
ContractSourceAddressSelector
from
'
./ContractSourceAddressSelector
'
;
...
@@ -114,10 +114,10 @@ const ContractDetails = ({ addressHash, channel, mainContractQuery }: Props) =>
...
@@ -114,10 +114,10 @@ const ContractDetails = ({ addressHash, channel, mainContractQuery }: Props) =>
<
RoutedTabs
<
RoutedTabs
tabs=
{
tabs
}
tabs=
{
tabs
}
isLoading=
{
isPlaceholderData
}
isLoading=
{
isPlaceholderData
}
variant=
"
radio_group
"
variant=
"
segmented
"
size=
"sm"
size=
"sm"
leftSlot=
{
addressSelector
}
leftSlot=
{
addressSelector
}
tabL
istProps=
{
TAB_LIST_PROPS
}
l
istProps=
{
TAB_LIST_PROPS
}
leftSlotProps=
{
LEFT_SLOT_PROPS
}
leftSlotProps=
{
LEFT_SLOT_PROPS
}
/>
/>
)
:
(
)
:
(
...
...
ui/address/contract/ContractSourceCode.tsx
View file @
27872bfe
import
{
Flex
,
Text
,
Tooltip
}
from
'
@chakra-ui/react
'
;
import
{
Flex
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SmartContract
}
from
'
types/api/contract
'
;
import
type
{
SmartContract
}
from
'
types/api/contract
'
;
...
@@ -6,9 +6,10 @@ import type { SmartContract } from 'types/api/contract';
...
@@ -6,9 +6,10 @@ import type { SmartContract } from 'types/api/contract';
import
{
route
}
from
'
nextjs-routes
'
;
import
{
route
}
from
'
nextjs-routes
'
;
import
formatLanguageName
from
'
lib/contracts/formatLanguageName
'
;
import
formatLanguageName
from
'
lib/contracts/formatLanguageName
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
LinkInternal
from
'
ui/shared/links/LinkInternal
'
;
import
CodeEditor
from
'
ui/shared/monaco/CodeEditor
'
;
import
CodeEditor
from
'
ui/shared/monaco/CodeEditor
'
;
import
formatFilePath
from
'
ui/shared/monaco/utils/formatFilePath
'
;
import
formatFilePath
from
'
ui/shared/monaco/utils/formatFilePath
'
;
...
@@ -54,10 +55,10 @@ export const ContractSourceCode = ({ data, isLoading, sourceAddress }: Props) =>
...
@@ -54,10 +55,10 @@ export const ContractSourceCode = ({ data, isLoading, sourceAddress }: Props) =>
},
[
data
]);
},
[
data
]);
const
heading
=
(
const
heading
=
(
<
Skeleton
isLoaded=
{
!
isLoading
}
fontWeight=
{
500
}
>
<
Skeleton
loading=
{
isLoading
}
fontWeight=
{
500
}
>
<
span
>
Contract source code
</
span
>
<
span
>
Contract source code
</
span
>
{
data
?.
language
&&
{
data
?.
language
&&
<
Text
whiteSpace=
"pre"
as=
"span"
variant=
"
secondary"
>
(
{
formatLanguageName
(
data
.
language
)
}
)
</
Text
>
}
<
Text
whiteSpace=
"pre"
as=
"span"
color=
"text.
secondary"
>
(
{
formatLanguageName
(
data
.
language
)
}
)
</
Text
>
}
</
Skeleton
>
</
Skeleton
>
);
);
...
@@ -66,16 +67,16 @@ export const ContractSourceCode = ({ data, isLoading, sourceAddress }: Props) =>
...
@@ -66,16 +67,16 @@ export const ContractSourceCode = ({ data, isLoading, sourceAddress }: Props) =>
null
;
null
;
const
diagramLink
=
data
?.
can_be_visualized_via_sol2uml
?
(
const
diagramLink
=
data
?.
can_be_visualized_via_sol2uml
?
(
<
Tooltip
label
=
"Visualize contract code using Sol2Uml JS library"
>
<
Tooltip
content
=
"Visualize contract code using Sol2Uml JS library"
>
<
Link
Internal
<
Link
href=
{
route
({
pathname
:
'
/visualize/sol2uml
'
,
query
:
{
address
:
sourceAddress
}
})
}
href=
{
route
({
pathname
:
'
/visualize/sol2uml
'
,
query
:
{
address
:
sourceAddress
}
})
}
ml=
{
{
base
:
'
0
'
,
lg
:
'
auto
'
}
}
ml=
{
{
base
:
'
0
'
,
lg
:
'
auto
'
}
}
isL
oading=
{
isLoading
}
l
oading=
{
isLoading
}
>
>
<
Skeleton
isLoaded=
{
!
isLoading
}
>
<
Skeleton
loading=
{
isLoading
}
>
View UML diagram
View UML diagram
</
Skeleton
>
</
Skeleton
>
</
Link
Internal
>
</
Link
>
</
Tooltip
>
</
Tooltip
>
)
:
null
;
)
:
null
;
...
@@ -83,7 +84,7 @@ export const ContractSourceCode = ({ data, isLoading, sourceAddress }: Props) =>
...
@@ -83,7 +84,7 @@ export const ContractSourceCode = ({ data, isLoading, sourceAddress }: Props) =>
<
ContractCodeIdes
hash=
{
sourceAddress
}
isLoading=
{
isLoading
}
/>
:
<
ContractCodeIdes
hash=
{
sourceAddress
}
isLoading=
{
isLoading
}
/>
:
null
;
null
;
const
copyToClipboard
=
data
&&
editorData
?.
length
===
1
?
(
const
copyToClipboard
=
data
&&
editorData
?.
length
===
1
&&
data
.
source_code
?
(
<
CopyToClipboard
<
CopyToClipboard
text=
{
data
.
source_code
}
text=
{
data
.
source_code
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
...
@@ -94,7 +95,7 @@ export const ContractSourceCode = ({ data, isLoading, sourceAddress }: Props) =>
...
@@ -94,7 +95,7 @@ export const ContractSourceCode = ({ data, isLoading, sourceAddress }: Props) =>
const
content
=
(()
=>
{
const
content
=
(()
=>
{
if
(
isLoading
)
{
if
(
isLoading
)
{
return
<
Skeleton
h=
"557px"
w=
"100%"
/>;
return
<
Skeleton
loading
h=
"557px"
w=
"100%"
/>;
}
}
if
(
!
editorData
)
{
if
(
!
editorData
)
{
...
...
ui/address/contract/alerts/ContractDetailsAlertProxyPattern.tsx
View file @
27872bfe
import
{
Alert
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SmartContractProxyType
}
from
'
types/api/contract
'
;
import
type
{
SmartContractProxyType
}
from
'
types/api/contract
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
import
{
Alert
}
from
'
toolkit/chakra/alert
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
interface
Props
{
interface
Props
{
type
:
NonNullable
<
SmartContractProxyType
>
;
type
:
NonNullable
<
SmartContractProxyType
>
;
...
@@ -70,10 +70,10 @@ const ContractCodeProxyPattern = ({ type }: Props) => {
...
@@ -70,10 +70,10 @@ const ContractCodeProxyPattern = ({ type }: Props) => {
}
}
return
(
return
(
<
Alert
status=
"warning"
flexWrap=
"wrap"
whiteSpace=
"pre-wrap"
>
<
Alert
status=
"warning"
whiteSpace=
"pre-wrap"
>
{
proxyInfo
.
link
?
(
{
proxyInfo
.
link
?
(
<>
<>
This proxy smart-contract is detected via
<
Link
External
href=
{
proxyInfo
.
link
}
>
{
proxyInfo
.
name
}
</
LinkExternal
>
This proxy smart-contract is detected via
<
Link
href=
{
proxyInfo
.
link
}
external
>
{
proxyInfo
.
name
}
</
Link
>
{
proxyInfo
.
description
&&
` - ${ proxyInfo.description }`
}
{
proxyInfo
.
description
&&
` - ${ proxyInfo.description }`
}
</>
</>
)
:
(
)
:
(
...
...
ui/address/contract/alerts/ContractDetailsAlertVerificationSource.tsx
View file @
27872bfe
import
{
Alert
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SmartContract
}
from
'
types/api/contract
'
;
import
type
{
SmartContract
}
from
'
types/api/contract
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
import
{
Alert
}
from
'
toolkit/chakra/alert
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
interface
Props
{
interface
Props
{
data
:
SmartContract
|
undefined
;
data
:
SmartContract
|
undefined
;
...
@@ -12,23 +12,24 @@ interface Props {
...
@@ -12,23 +12,24 @@ interface Props {
const
ContractDetailsAlertVerificationSource
=
({
data
}:
Props
)
=>
{
const
ContractDetailsAlertVerificationSource
=
({
data
}:
Props
)
=>
{
if
(
data
?.
is_verified_via_eth_bytecode_db
)
{
if
(
data
?.
is_verified_via_eth_bytecode_db
)
{
return
(
return
(
<
Alert
status=
"warning"
whiteSpace=
"pre-wrap"
flexWrap=
"wrap"
>
<
Alert
status=
"warning"
whiteSpace=
"pre-wrap"
>
<
span
>
This contract has been
{
data
.
is_partially_verified
?
'
partially
'
:
''
}
verified using
</
span
>
<
span
>
This contract has been
{
data
.
is_partially_verified
?
'
partially
'
:
''
}
verified using
</
span
>
<
Link
External
<
Link
href=
"https://docs.blockscout.com/about/features/ethereum-bytecode-database-microservice"
href=
"https://docs.blockscout.com/about/features/ethereum-bytecode-database-microservice"
fontSize=
"md"
textStyle=
"md"
external
>
>
Blockscout Bytecode Database
Blockscout Bytecode Database
</
Link
External
>
</
Link
>
</
Alert
>
</
Alert
>
);
);
}
}
if
(
data
?.
is_verified_via_sourcify
)
{
if
(
data
?.
is_verified_via_sourcify
)
{
return
(
return
(
<
Alert
status=
"warning"
whiteSpace=
"pre-wrap"
flexWrap=
"wrap"
>
<
Alert
status=
"warning"
whiteSpace=
"pre-wrap"
>
<
span
>
This contract has been
{
data
.
is_partially_verified
?
'
partially
'
:
''
}
verified via Sourcify.
</
span
>
<
span
>
This contract has been
{
data
.
is_partially_verified
?
'
partially
'
:
''
}
verified via Sourcify.
</
span
>
{
data
.
sourcify_repo_url
&&
<
Link
External
href=
{
data
.
sourcify_repo_url
}
fontSize=
"md"
>
View contract in Sourcify repository
</
LinkExternal
>
}
{
data
.
sourcify_repo_url
&&
<
Link
href=
{
data
.
sourcify_repo_url
}
textStyle=
"md"
external
>
View contract in Sourcify repository
</
Link
>
}
</
Alert
>
</
Alert
>
);
);
}
}
...
...
ui/address/contract/alerts/ContractDetailsAlerts.tsx
View file @
27872bfe
import
{
chakra
,
Alert
,
Box
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Box
,
Flex
}
from
'
@chakra-ui/react
'
;
import
type
{
Channel
}
from
'
phoenix
'
;
import
type
{
Channel
}
from
'
phoenix
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
...
@@ -8,10 +8,10 @@ import type { SmartContract } from 'types/api/contract';
...
@@ -8,10 +8,10 @@ import type { SmartContract } from 'types/api/contract';
import
{
route
}
from
'
nextjs-routes
'
;
import
{
route
}
from
'
nextjs-routes
'
;
import
useSocketMessage
from
'
lib/socket/useSocketMessage
'
;
import
useSocketMessage
from
'
lib/socket/useSocketMessage
'
;
import
Skeleton
from
'
ui/shared/chakra/Skeleton
'
;
import
{
Alert
}
from
'
toolkit/chakra/alert
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/skeleton
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
AddressEntity
from
'
ui/shared/entities/address/AddressEntity
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
import
LinkInternal
from
'
ui/shared/links/LinkInternal
'
;
import
ContractDetailsVerificationButton
from
'
../ContractDetailsVerificationButton
'
;
import
ContractDetailsVerificationButton
from
'
../ContractDetailsVerificationButton
'
;
import
ContractDetailsAlertProxyPattern
from
'
./ContractDetailsAlertProxyPattern
'
;
import
ContractDetailsAlertProxyPattern
from
'
./ContractDetailsAlertProxyPattern
'
;
...
@@ -42,14 +42,14 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
...
@@ -42,14 +42,14 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
{
data
?.
is_blueprint
&&
(
{
data
?.
is_blueprint
&&
(
<
Box
>
<
Box
>
<
span
>
This is an
</
span
>
<
span
>
This is an
</
span
>
<
Link
E
xternal
href=
"https://eips.ethereum.org/EIPS/eip-5202"
>
<
Link
e
xternal
href=
"https://eips.ethereum.org/EIPS/eip-5202"
>
ERC-5202 Blueprint contract
ERC-5202 Blueprint contract
</
Link
External
>
</
Link
>
</
Box
>
</
Box
>
)
}
)
}
{
data
?.
is_verified
&&
(
{
data
?.
is_verified
&&
(
<
Skeleton
isLoaded=
{
!
isLoading
}
>
<
Skeleton
loading=
{
isLoading
}
>
<
Alert
status=
"success"
flexWrap=
"wrap"
rowGap=
{
3
}
columnGap=
{
5
}
>
<
Alert
status=
"success"
descriptionProps=
{
{
alignItems
:
'
center
'
,
flexWrap
:
'
wrap
'
,
rowGap
:
3
,
columnGap
:
5
}
}
>
<
span
>
Contract Source Code Verified (
{
data
.
is_partially_verified
?
'
Partial
'
:
'
Exact
'
}
Match)
</
span
>
<
span
>
Contract Source Code Verified (
{
data
.
is_partially_verified
?
'
Partial
'
:
'
Exact
'
}
Match)
</
span
>
{
{
data
.
is_partially_verified
?
(
data
.
is_partially_verified
?
(
...
@@ -70,7 +70,7 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
...
@@ -70,7 +70,7 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
</
Alert
>
</
Alert
>
)
}
)
}
{
!
data
?.
is_verified
&&
data
?.
verified_twin_address_hash
&&
(
!
data
?.
proxy_type
||
data
.
proxy_type
===
'
unknown
'
)
&&
(
{
!
data
?.
is_verified
&&
data
?.
verified_twin_address_hash
&&
(
!
data
?.
proxy_type
||
data
.
proxy_type
===
'
unknown
'
)
&&
(
<
Alert
status=
"warning"
whiteSpace=
"pre-wrap"
flexWrap=
"wrap"
>
<
Alert
status=
"warning"
whiteSpace=
"pre-wrap"
>
<
span
>
Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB
</
span
>
<
span
>
Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB
</
span
>
<
AddressEntity
<
AddressEntity
address=
{
{
hash
:
data
.
verified_twin_address_hash
,
filecoin
:
{
robust
:
data
.
verified_twin_filecoin_robust_address
},
is_contract
:
true
}
}
address=
{
{
hash
:
data
.
verified_twin_address_hash
,
filecoin
:
{
robust
:
data
.
verified_twin_filecoin_robust_address
},
is_contract
:
true
}
}
...
@@ -79,9 +79,9 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
...
@@ -79,9 +79,9 @@ const ContractDetailsAlerts = ({ data, isLoading, addressHash, channel }: Props)
fontWeight=
"500"
fontWeight=
"500"
/>
/>
<
chakra
.
span
mt=
{
1
}
>
All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with
</
chakra
.
span
>
<
chakra
.
span
mt=
{
1
}
>
All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with
</
chakra
.
span
>
<
Link
Internal
href=
{
route
({
pathname
:
'
/address/[hash]/contract-verification
'
,
query
:
{
hash
:
addressHash
}
})
}
>
<
Link
href=
{
route
({
pathname
:
'
/address/[hash]/contract-verification
'
,
query
:
{
hash
:
addressHash
}
})
}
>
Verify
&
Publish
Verify
&
Publish
</
Link
Internal
>
</
Link
>
<
span
>
page
</
span
>
<
span
>
page
</
span
>
</
Alert
>
</
Alert
>
)
}
)
}
...
...
ui/address/contract/audits/ContractSecurityAudits.tsx
View file @
27872bfe
import
{
Box
,
Button
,
useDisclosure
}
from
'
@chakra-ui/react
'
;
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SmartContractSecurityAuditSubmission
}
from
'
types/api/contract
'
;
import
type
{
SmartContractSecurityAuditSubmission
}
from
'
types/api/contract
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
useDisclosure
}
from
'
toolkit/hooks/useDisclosure
'
;
import
ContainerWithScrollY
from
'
ui/shared/ContainerWithScrollY
'
;
import
ContainerWithScrollY
from
'
ui/shared/ContainerWithScrollY
'
;
import
FormModal
from
'
ui/shared/FormModal
'
;
import
FormModal
from
'
ui/shared/FormModal
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
import
ContractSubmitAuditForm
from
'
./ContractSubmitAuditForm
'
;
import
ContractSubmitAuditForm
from
'
./ContractSubmitAuditForm
'
;
...
@@ -46,16 +48,16 @@ const ContractSecurityAudits = ({ addressHash }: Props) => {
...
@@ -46,16 +48,16 @@ const ContractSecurityAudits = ({ addressHash }: Props) => {
mt=
{
2
}
mt=
{
2
}
>
>
{
data
.
items
.
map
(
item
=>
(
{
data
.
items
.
map
(
item
=>
(
<
Link
External
href=
{
item
.
audit_report_url
}
key=
{
item
.
audit_company_name
+
item
.
audit_publish_date
}
isL
oading=
{
isPlaceholderData
}
>
<
Link
external
href=
{
item
.
audit_report_url
}
key=
{
item
.
audit_company_name
+
item
.
audit_publish_date
}
l
oading=
{
isPlaceholderData
}
>
{
`${ item.audit_company_name }, ${ dayjs(item.audit_publish_date).format('MMM DD, YYYY') }`
}
{
`${ item.audit_company_name }, ${ dayjs(item.audit_publish_date).format('MMM DD, YYYY') }`
}
</
Link
External
>
</
Link
>
))
}
))
}
</
ContainerWithScrollY
>
</
ContainerWithScrollY
>
</
Box
>
</
Box
>
)
}
)
}
<
FormModal
<
SmartContractSecurityAuditSubmission
>
<
FormModal
<
SmartContractSecurityAuditSubmission
>
isOpen=
{
modalProps
.
isO
pen
}
open=
{
modalProps
.
o
pen
}
on
Close=
{
modalProps
.
onClos
e
}
on
OpenChange=
{
modalProps
.
onOpenChang
e
}
title=
{
formTitle
}
title=
{
formTitle
}
renderForm=
{
renderForm
}
renderForm=
{
renderForm
}
/
>
/
>
...
...
ui/address/contract/audits/ContractSubmitAuditForm.tsx
View file @
27872bfe
import
{
Button
,
VStack
}
from
'
@chakra-ui/react
'
;
import
{
VStack
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SubmitHandler
}
from
'
react-hook-form
'
;
import
type
{
SubmitHandler
}
from
'
react-hook-form
'
;
import
{
FormProvider
,
useForm
}
from
'
react-hook-form
'
;
import
{
FormProvider
,
useForm
}
from
'
react-hook-form
'
;
...
@@ -8,7 +8,8 @@ import type { SmartContractSecurityAuditSubmission } from 'types/api/contract';
...
@@ -8,7 +8,8 @@ import type { SmartContractSecurityAuditSubmission } from 'types/api/contract';
import
type
{
ResourceError
}
from
'
lib/api/resources
'
;
import
type
{
ResourceError
}
from
'
lib/api/resources
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
useApiFetch
from
'
lib/api/useApiFetch
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
useToast
from
'
lib/hooks/useToast
'
;
import
{
Button
}
from
'
toolkit/chakra/button
'
;
import
{
toaster
}
from
'
toolkit/chakra/toaster
'
;
import
FormFieldCheckbox
from
'
ui/shared/forms/fields/FormFieldCheckbox
'
;
import
FormFieldCheckbox
from
'
ui/shared/forms/fields/FormFieldCheckbox
'
;
import
FormFieldEmail
from
'
ui/shared/forms/fields/FormFieldEmail
'
;
import
FormFieldEmail
from
'
ui/shared/forms/fields/FormFieldEmail
'
;
import
FormFieldText
from
'
ui/shared/forms/fields/FormFieldText
'
;
import
FormFieldText
from
'
ui/shared/forms/fields/FormFieldText
'
;
...
@@ -39,7 +40,6 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
...
@@ -39,7 +40,6 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
const
containerRef
=
React
.
useRef
<
HTMLFormElement
>
(
null
);
const
containerRef
=
React
.
useRef
<
HTMLFormElement
>
(
null
);
const
apiFetch
=
useApiFetch
();
const
apiFetch
=
useApiFetch
();
const
toast
=
useToast
();
const
formApi
=
useForm
<
Inputs
>
({
const
formApi
=
useForm
<
Inputs
>
({
mode
:
'
onTouched
'
,
mode
:
'
onTouched
'
,
...
@@ -57,13 +57,9 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
...
@@ -57,13 +57,9 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
},
},
});
});
toast
({
toaster
.
success
({
position
:
'
top-right
'
,
title
:
'
Success
'
,
title
:
'
Success
'
,
description
:
'
Your audit report has been successfully submitted for review
'
,
description
:
'
Your audit report has been successfully submitted for review
'
,
status
:
'
success
'
,
variant
:
'
subtle
'
,
isClosable
:
true
,
});
});
onSuccess
();
onSuccess
();
...
@@ -77,37 +73,32 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
...
@@ -77,37 +73,32 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
setError
(
errorField
,
{
type
:
'
custom
'
,
message
:
errorMap
[
errorField
].
join
(
'
,
'
)
});
setError
(
errorField
,
{
type
:
'
custom
'
,
message
:
errorMap
[
errorField
].
join
(
'
,
'
)
});
});
});
}
else
{
}
else
{
toast
({
toaster
.
error
({
position
:
'
top-right
'
,
title
:
'
Error
'
,
title
:
'
Error
'
,
description
:
(
_error
as
ResourceError
<
{
message
:
string
}
>
)?.
payload
?.
message
||
'
Something went wrong. Try again later.
'
,
description
:
(
_error
as
ResourceError
<
{
message
:
string
}
>
)?.
payload
?.
message
||
'
Something went wrong. Try again later.
'
,
status
:
'
error
'
,
variant
:
'
subtle
'
,
isClosable
:
true
,
});
});
}
}
}
}
},
[
apiFetch
,
address
,
toast
,
setError
,
onSuccess
]);
},
[
apiFetch
,
address
,
setError
,
onSuccess
]);
return
(
return
(
<
FormProvider
{
...
formApi
}
>
<
FormProvider
{
...
formApi
}
>
<
form
noValidate
onSubmit=
{
handleSubmit
(
onFormSubmit
)
}
autoComplete=
"off"
ref=
{
containerRef
}
>
<
form
noValidate
onSubmit=
{
handleSubmit
(
onFormSubmit
)
}
autoComplete=
"off"
ref=
{
containerRef
}
>
<
VStack
gap=
{
5
}
alignItems=
"flex-start"
>
<
VStack
gap=
{
5
}
alignItems=
"flex-start"
>
<
FormFieldText
<
Inputs
>
name="submitter_name"
isR
equired placeholder="Submitter name"/
>
<
FormFieldText
<
Inputs
>
name="submitter_name"
r
equired placeholder="Submitter name"/
>
<
FormFieldEmail
<
Inputs
>
name="submitter_email"
isR
equired placeholder="Submitter email"/
>
<
FormFieldEmail
<
Inputs
>
name="submitter_email"
r
equired placeholder="Submitter email"/
>
<
FormFieldCheckbox
<
Inputs
,
'
is_project_owner
'
>
<
FormFieldCheckbox
<
Inputs
,
'
is_project_owner
'
>
name="is_project_owner"
name="is_project_owner"
label="I'm the contract owner"
label="I'm the contract owner"
/
>
/
>
<
FormFieldText
<
Inputs
>
name="project_name"
isR
equired placeholder="Project name"/
>
<
FormFieldText
<
Inputs
>
name="project_name"
r
equired placeholder="Project name"/
>
<
FormFieldUrl
<
Inputs
>
name="project_url"
isR
equired placeholder="Project URL"/
>
<
FormFieldUrl
<
Inputs
>
name="project_url"
r
equired placeholder="Project URL"/
>
<
FormFieldText
<
Inputs
>
name="audit_company_name"
isR
equired placeholder="Audit company name"/
>
<
FormFieldText
<
Inputs
>
name="audit_company_name"
r
equired placeholder="Audit company name"/
>
<
FormFieldUrl
<
Inputs
>
name="audit_report_url"
isR
equired placeholder="Audit report URL"/
>
<
FormFieldUrl
<
Inputs
>
name="audit_report_url"
r
equired placeholder="Audit report URL"/
>
<
FormFieldText
<
Inputs
>
<
FormFieldText
<
Inputs
>
name="audit_publish_date"
name="audit_publish_date"
type="date"
inputProps=
{
{
type
:
'
date
'
,
max
:
dayjs
().
format
(
'
YYYY-MM-DD
'
)
}
}
max=
{
dayjs
().
format
(
'
YYYY-MM-DD
'
)
}
required
isRequired
placeholder="Audit publish date"
placeholder="Audit publish date"
/
>
/
>
<
FormFieldText
<
Inputs
>
<
FormFieldText
<
Inputs
>
...
@@ -122,9 +113,9 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
...
@@ -122,9 +113,9 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
type=
"submit"
type=
"submit"
size=
"lg"
size=
"lg"
mt=
{
8
}
mt=
{
8
}
isL
oading=
{
formState
.
isSubmitting
}
l
oading=
{
formState
.
isSubmitting
}
loadingText=
"Send request"
loadingText=
"Send request"
isD
isabled=
{
!
formState
.
isDirty
}
d
isabled=
{
!
formState
.
isDirty
}
>
>
Send request
Send request
</
Button
>
</
Button
>
...
...
ui/address/contract/info/ContractDetailsInfo.tsx
View file @
27872bfe
...
@@ -6,9 +6,9 @@ import type { SmartContract } from 'types/api/contract';
...
@@ -6,9 +6,9 @@ import type { SmartContract } from 'types/api/contract';
import
config
from
'
configs/app
'
;
import
config
from
'
configs/app
'
;
import
{
CONTRACT_LICENSES
}
from
'
lib/contracts/licenses
'
;
import
{
CONTRACT_LICENSES
}
from
'
lib/contracts/licenses
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
{
Link
}
from
'
toolkit/chakra/link
'
;
import
{
getGitHubOwnerAndRepo
}
from
'
ui/contractVerification/utils
'
;
import
{
getGitHubOwnerAndRepo
}
from
'
ui/contractVerification/utils
'
;
import
ContractCertifiedLabel
from
'
ui/shared/ContractCertifiedLabel
'
;
import
ContractCertifiedLabel
from
'
ui/shared/ContractCertifiedLabel
'
;
import
LinkExternal
from
'
ui/shared/links/LinkExternal
'
;
import
ContractSecurityAudits
from
'
../audits/ContractSecurityAudits
'
;
import
ContractSecurityAudits
from
'
../audits/ContractSecurityAudits
'
;
import
ContractDetailsInfoItem
from
'
./ContractDetailsInfoItem
'
;
import
ContractDetailsInfoItem
from
'
./ContractDetailsInfoItem
'
;
...
@@ -40,9 +40,9 @@ const ContractDetailsInfo = ({ data, isLoading, addressHash }: Props) => {
...
@@ -40,9 +40,9 @@ const ContractDetailsInfo = ({ data, isLoading, addressHash }: Props) => {
}
}
return
(
return
(
<
Link
E
xternal
href=
{
license
.
url
}
>
<
Link
e
xternal
href=
{
license
.
url
}
>
{
license
.
label
}
{
license
.
label
}
</
Link
External
>
</
Link
>
);
);
})();
})();
...
@@ -57,9 +57,9 @@ const ContractDetailsInfo = ({ data, isLoading, addressHash }: Props) => {
...
@@ -57,9 +57,9 @@ const ContractDetailsInfo = ({ data, isLoading, addressHash }: Props) => {
const
commit
=
data
.
github_repository_metadata
.
commit
;
const
commit
=
data
.
github_repository_metadata
.
commit
;
const
pathPrefix
=
data
.
github_repository_metadata
.
path_prefix
;
const
pathPrefix
=
data
.
github_repository_metadata
.
path_prefix
;
return
(
return
(
<
Link
E
xternal
href=
{
`${ repoUrl }/tree/${ commit }${ pathPrefix ? `
/
$
{
pathPrefix
}
` : '' }`
}
>
<
Link
e
xternal
href=
{
`${ repoUrl }/tree/${ commit }${ pathPrefix ? `
/
$
{
pathPrefix
}
` : '' }`
}
>
{
owner
&&
repo
?
`${ owner }/${ repo }`
:
data
.
github_repository_metadata
.
repository_url
}
{
owner
&&
repo
?
`${ owner }/${ repo }`
:
data
.
github_repository_metadata
.
repository_url
}
</
Link
External
>
</
Link
>
);
);
})();
})();
...
@@ -70,90 +70,102 @@ const ContractDetailsInfo = ({ data, isLoading, addressHash }: Props) => {
...
@@ -70,90 +70,102 @@ const ContractDetailsInfo = ({ data, isLoading, addressHash }: Props) => {
{
data
.
name
&&
(
{
data
.
name
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"Contract name"
label=
"Contract name"
content=
{
contractNameWithCertifiedIcon
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
contractNameWithCertifiedIcon
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
data
.
compiler_version
&&
(
{
data
.
compiler_version
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"Compiler version"
label=
"Compiler version"
content=
{
data
.
compiler_version
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
data
.
compiler_version
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
data
.
zk_compiler_version
&&
(
{
data
.
zk_compiler_version
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"ZK compiler version"
label=
"ZK compiler version"
content=
{
data
.
zk_compiler_version
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
data
.
zk_compiler_version
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
data
.
evm_version
&&
(
{
data
.
evm_version
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"EVM version"
label=
"EVM version"
content=
{
data
.
evm_version
}
textTransform=
"capitalize"
textTransform=
"capitalize"
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
data
.
evm_version
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
licenseLink
&&
(
{
licenseLink
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"License"
label=
"License"
content=
{
licenseLink
}
hint=
"License type is entered manually during verification. The initial source code may contain a different license type than the one displayed."
hint=
"License type is entered manually during verification. The initial source code may contain a different license type than the one displayed."
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
licenseLink
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
typeof
data
.
optimization_enabled
===
'
boolean
'
&&
!
isStylusContract
&&
(
{
typeof
data
.
optimization_enabled
===
'
boolean
'
&&
!
isStylusContract
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"Optimization enabled"
label=
"Optimization enabled"
content=
{
data
.
optimization_enabled
?
'
true
'
:
'
false
'
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
data
.
optimization_enabled
?
'
true
'
:
'
false
'
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
data
.
optimization_runs
!==
null
&&
!
isStylusContract
&&
(
{
data
.
optimization_runs
!==
null
&&
!
isStylusContract
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
{
rollupFeature
.
isEnabled
&&
rollupFeature
.
type
===
'
zkSync
'
?
'
Optimization mode
'
:
'
Optimization runs
'
}
label=
{
rollupFeature
.
isEnabled
&&
rollupFeature
.
type
===
'
zkSync
'
?
'
Optimization mode
'
:
'
Optimization runs
'
}
content=
{
String
(
data
.
optimization_runs
)
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
String
(
data
.
optimization_runs
)
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
data
.
package_name
&&
(
{
data
.
package_name
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"Package name"
label=
"Package name"
content=
{
data
.
package_name
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
data
.
package_name
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
data
.
verified_at
&&
(
{
data
.
verified_at
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"Verified at"
label=
"Verified at"
content=
{
dayjs
(
data
.
verified_at
).
format
(
'
llll
'
)
}
wordBreak=
"break-word"
wordBreak=
"break-word"
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
dayjs
(
data
.
verified_at
).
format
(
'
llll
'
)
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
data
.
file_path
&&
!
isStylusContract
&&
(
{
data
.
file_path
&&
!
isStylusContract
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"Contract file path"
label=
"Contract file path"
content=
{
data
.
file_path
}
wordBreak=
"break-word"
wordBreak=
"break-word"
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
data
.
file_path
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
sourceCodeLink
&&
(
{
sourceCodeLink
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"Source code"
label=
"Source code"
content=
{
sourceCodeLink
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
{
sourceCodeLink
}
</
ContractDetailsInfoItem
>
)
}
)
}
{
config
.
UI
.
hasContractAuditReports
&&
(
{
config
.
UI
.
hasContractAuditReports
&&
(
<
ContractDetailsInfoItem
<
ContractDetailsInfoItem
label=
"Security audit"
label=
"Security audit"
content=
{
<
ContractSecurityAudits
addressHash=
{
addressHash
}
/>
}
isLoading=
{
isLoading
}
isLoading=
{
isLoading
}
/>
>
<
ContractSecurityAudits
addressHash=
{
addressHash
}
/>
</
ContractDetailsInfoItem
>
)
}
)
}
</
Grid
>
</
Grid
>
);
);
...
...
ui/address/contract/info/ContractDetailsInfoItem.tsx
View file @
27872bfe
import
{
chakra
,
useColorModeValue
,
Flex
,
GridItem
}
from
'
@chakra-ui/react
'
;
import
{
chakra
,
Flex
,
GridItem
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
Skeleton
from
'
ui/shared/chakra/S
keleton
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/s
keleton
'
;
import
Hint
from
'
ui/shared/Hint
'
;
import
Hint
from
'
ui/shared/Hint
'
;
interface
Props
{
interface
Props
{
label
:
string
;
label
:
string
;
c
ontent
:
string
|
React
.
ReactNode
;
c
hildren
:
React
.
ReactNode
;
className
?:
string
;
className
?:
string
;
isLoading
:
boolean
;
isLoading
:
boolean
;
hint
?:
string
;
hint
?:
string
;
}
}
const
ContractDetailsInfoItem
=
({
label
,
content
,
className
,
isLoading
,
hint
}:
Props
)
=>
{
const
ContractDetailsInfoItem
=
({
label
,
children
,
className
,
isLoading
,
hint
}:
Props
)
=>
{
const
hintIconColor
=
useColorModeValue
(
'
gray.600
'
,
'
gray.400
'
);
return
(
return
(
<
GridItem
display=
"flex"
columnGap=
{
6
}
wordBreak=
"break-all"
className=
{
className
}
alignItems=
"baseline"
>
<
GridItem
display=
"flex"
columnGap=
{
6
}
wordBreak=
"break-all"
className=
{
className
}
alignItems=
"baseline"
>
<
Skeleton
isLoaded=
{
!
isLoading
}
w=
"170px"
flexShrink=
{
0
}
fontWeight=
{
500
}
>
<
Skeleton
loading=
{
isLoading
}
w=
"170px"
flexShrink=
{
0
}
fontWeight=
{
500
}
>
<
Flex
alignItems=
"center"
>
<
Flex
alignItems=
"center"
>
{
label
}
{
label
}
{
hint
&&
(
{
hint
&&
(
<
Hint
<
Hint
label=
{
hint
}
label=
{
hint
}
ml=
{
2
}
ml=
{
2
}
color=
{
hintIconColor
}
color=
{
{
_light
:
'
gray.600
'
,
_dark
:
'
gray.400
'
}
}
tooltipProps=
{
{
p
lacement
:
'
bottom
'
}
}
tooltipProps=
{
{
p
ositioning
:
{
placement
:
'
bottom
'
}
}
}
/>
/>
)
}
)
}
</
Flex
>
</
Flex
>
</
Skeleton
>
</
Skeleton
>
<
Skeleton
isLoaded=
{
!
isLoading
}
>
{
content
}
</
Skeleton
>
<
Skeleton
loading=
{
isLoading
}
>
{
children
}
</
Skeleton
>
</
GridItem
>
</
GridItem
>
);
);
};
};
...
...
ui/address/contract/useContractDetailsTabs.tsx
View file @
27872bfe
import
{
Alert
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
Flex
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SmartContract
}
from
'
types/api/contract
'
;
import
type
{
SmartContract
}
from
'
types/api/contract
'
;
import
{
Alert
}
from
'
toolkit/chakra/alert
'
;
import
CodeViewSnippet
from
'
ui/shared/CodeViewSnippet
'
;
import
CodeViewSnippet
from
'
ui/shared/CodeViewSnippet
'
;
import
RawDataSnippet
from
'
ui/shared/RawDataSnippet
'
;
import
RawDataSnippet
from
'
ui/shared/RawDataSnippet
'
;
...
...
ui/address/contract/useContractTabs.tsx
View file @
27872bfe
...
@@ -74,12 +74,12 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
...
@@ -74,12 +74,12 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
return React.useMemo(() => {
return React.useMemo(() => {
return {
return {
tabs: [
tabs: [
//
data?.hash && {
data?.hash && {
//
id: 'contract_code' as const,
id: 'contract_code' as const,
//
title: 'Code',
title: 'Code',
//
component: <ContractDetails mainContractQuery={ contractQuery } channel={ channel } addressHash={ data.hash }/>,
component: <ContractDetails mainContractQuery={ contractQuery } channel={ channel } addressHash={ data.hash }/>,
//
subTabs: CONTRACT_DETAILS_TAB_IDS as unknown as Array<string>,
subTabs: CONTRACT_DETAILS_TAB_IDS as unknown as Array<string>,
//
},
},
// contractQuery.data?.abi && {
// contractQuery.data?.abi && {
// id: [ 'read_write_contract' as const, 'read_contract' as const, 'write_contract' as const ],
// id: [ 'read_write_contract' as const, 'read_contract' as const, 'write_contract' as const ],
// title: 'Read/Write contract',
// title: 'Read/Write contract',
...
...
ui/pages/Address.tsx
View file @
27872bfe
...
@@ -235,29 +235,29 @@ const AddressPageContent = () => {
...
@@ -235,29 +235,29 @@ const AddressPageContent = () => {
} :
} :
undefined,
undefined,
//
addressQuery.data?.is_contract ? {
addressQuery.data?.is_contract ? {
//
id: 'contract',
id: 'contract',
//
title: () => {
title: () => {
//
if (addressQuery.data.is_verified) {
if (addressQuery.data.is_verified) {
//
return (
return (
//
<>
<>
//
<span>Contract</span>
<span>Contract</span>
//
<IconSvg name="status/success" boxSize="14px" color="green.500" ml={ 1 }/>
<IconSvg name="status/success" boxSize="14px" color="green.500" ml={ 1 }/>
//
</>
</>
//
);
);
//
}
}
//
return 'Contract';
return 'Contract';
//
},
},
//
component: (
component: (
//
<AddressContract
<AddressContract
//
tabs={ contractTabs.tabs }
tabs={ contractTabs.tabs }
//
shouldRender={ !isTabsLoading }
shouldRender={ !isTabsLoading }
//
isLoading={ contractTabs.isLoading }
isLoading={ contractTabs.isLoading }
//
/>
/>
//
),
),
//
subTabs: CONTRACT_TAB_IDS,
subTabs: CONTRACT_TAB_IDS,
//
} : undefined,
} : undefined,
].filter(Boolean);
].filter(Boolean);
}, [
}, [
addressQuery.data,
addressQuery.data,
...
...
ui/shared/CodeViewSnippet.tsx
View file @
27872bfe
import
{
Box
,
chakra
,
Flex
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
chakra
,
Flex
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
Skeleton
from
'
ui/shared/chakra/S
keleton
'
;
import
{
Skeleton
}
from
'
toolkit/chakra/s
keleton
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
CodeEditor
from
'
ui/shared/monaco/CodeEditor
'
;
import
CodeEditor
from
'
ui/shared/monaco/CodeEditor
'
;
...
@@ -25,12 +25,12 @@ const CodeViewSnippet = ({ data, copyData, language, title, className, rightSlot
...
@@ -25,12 +25,12 @@ const CodeViewSnippet = ({ data, copyData, language, title, className, rightSlot
<
Box
className=
{
className
}
as=
"section"
title=
{
title
}
>
<
Box
className=
{
className
}
as=
"section"
title=
{
title
}
>
{
(
title
||
rightSlot
)
&&
(
{
(
title
||
rightSlot
)
&&
(
<
Flex
justifyContent=
{
title
?
'
space-between
'
:
'
flex-end
'
}
alignItems=
"center"
mb=
{
3
}
>
<
Flex
justifyContent=
{
title
?
'
space-between
'
:
'
flex-end
'
}
alignItems=
"center"
mb=
{
3
}
>
{
title
&&
<
Skeleton
fontWeight=
{
500
}
isLoaded=
{
!
isLoading
}
>
{
title
}
</
Skeleton
>
}
{
title
&&
<
Skeleton
loading=
{
isLoading
}
fontWeight=
{
500
}
>
{
title
}
</
Skeleton
>
}
{
rightSlot
}
{
rightSlot
}
<
CopyToClipboard
text=
{
copyData
??
data
}
isLoading=
{
isLoading
}
/>
<
CopyToClipboard
text=
{
copyData
??
data
}
isLoading=
{
isLoading
}
/>
</
Flex
>
</
Flex
>
)
}
)
}
{
isLoading
?
<
Skeleton
height=
"500px"
w=
"100%"
/>
:
<
CodeEditor
data=
{
editorData
}
language=
{
language
}
/>
}
{
isLoading
?
<
Skeleton
loading
height=
"500px"
w=
"100%"
/>
:
<
CodeEditor
data=
{
editorData
}
language=
{
language
}
/>
}
</
Box
>
</
Box
>
);
);
};
};
...
...
ui/shared/ad/CoinzillaTextAd.tsx
View file @
27872bfe
...
@@ -87,7 +87,7 @@ const CoinzillaTextAd = ({ className }: { className?: string }) => {
...
@@ -87,7 +87,7 @@ const CoinzillaTextAd = ({ className }: { className?: string }) => {
src=
{
adData
.
ad
.
thumbnail
}
src=
{
adData
.
ad
.
thumbnail
}
width=
"20px"
width=
"20px"
height=
"20px"
height=
"20px"
mb=
"
-4
px"
mb=
"
2
px"
mr=
{
1
}
mr=
{
1
}
display=
"inline-block"
display=
"inline-block"
alt=
""
alt=
""
...
...
ui/shared/forms/fields/FormFieldText.tsx
View file @
27872bfe
import
type
{
HTMLChakraProps
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
FieldValues
,
Path
}
from
'
react-hook-form
'
;
import
type
{
FieldValues
,
Path
}
from
'
react-hook-form
'
;
import
{
useController
,
useFormContext
}
from
'
react-hook-form
'
;
import
{
useController
,
useFormContext
}
from
'
react-hook-form
'
;
...
@@ -6,7 +5,9 @@ import { useController, useFormContext } from 'react-hook-form';
...
@@ -6,7 +5,9 @@ import { useController, useFormContext } from 'react-hook-form';
import
type
{
FormFieldPropsBase
}
from
'
./types
'
;
import
type
{
FormFieldPropsBase
}
from
'
./types
'
;
import
{
Field
}
from
'
toolkit/chakra/field
'
;
import
{
Field
}
from
'
toolkit/chakra/field
'
;
import
type
{
InputProps
}
from
'
toolkit/chakra/input
'
;
import
{
Input
}
from
'
toolkit/chakra/input
'
;
import
{
Input
}
from
'
toolkit/chakra/input
'
;
import
type
{
TextareaProps
}
from
'
toolkit/chakra/textarea
'
;
import
{
Textarea
}
from
'
toolkit/chakra/textarea
'
;
import
{
Textarea
}
from
'
toolkit/chakra/textarea
'
;
import
getFieldErrorText
from
'
../utils/getFieldErrorText
'
;
import
getFieldErrorText
from
'
../utils/getFieldErrorText
'
;
...
@@ -49,14 +50,14 @@ const FormFieldText = <
...
@@ -49,14 +50,14 @@ const FormFieldText = <
<
Textarea
<
Textarea
{
...
field
}
{
...
field
}
autoComplete=
"off"
autoComplete=
"off"
{
...
inputProps
as
HTMLChakraProps
<'
textarea
'
>
}
{
...
inputProps
as
TextareaProps
}
onBlur=
{
handleBlur
}
onBlur=
{
handleBlur
}
/>
/>
)
:
(
)
:
(
<
Input
<
Input
{
...
field
}
{
...
field
}
autoComplete=
"off"
autoComplete=
"off"
{
...
inputProps
as
HTMLChakraProps
<'
input
'
>
}
{
...
inputProps
as
InputProps
}
onBlur=
{
handleBlur
}
onBlur=
{
handleBlur
}
/>
/>
);
);
...
...
ui/shared/forms/fields/types.ts
View file @
27872bfe
import
type
{
HTMLChakraProps
}
from
'
@chakra-ui/react
'
;
import
type
React
from
'
react
'
;
import
type
React
from
'
react
'
;
import
type
{
ControllerRenderProps
,
FieldValues
,
Path
,
RegisterOptions
}
from
'
react-hook-form
'
;
import
type
{
ControllerRenderProps
,
FieldValues
,
Path
,
RegisterOptions
}
from
'
react-hook-form
'
;
import
type
{
FieldProps
}
from
'
toolkit/chakra/field
'
;
import
type
{
FieldProps
}
from
'
toolkit/chakra/field
'
;
import
type
{
InputProps
}
from
'
toolkit/chakra/input
'
;
import
type
{
TextareaProps
}
from
'
toolkit/chakra/textarea
'
;
export
interface
FormFieldPropsBase
<
export
interface
FormFieldPropsBase
<
FormFields
extends
FieldValues
,
FormFields
extends
FieldValues
,
...
@@ -14,5 +15,5 @@ export interface FormFieldPropsBase<
...
@@ -14,5 +15,5 @@ export interface FormFieldPropsBase<
onBlur
?:
()
=>
void
;
onBlur
?:
()
=>
void
;
onChange
?:
()
=>
void
;
onChange
?:
()
=>
void
;
rightElement
?:
({
field
}:
{
field
:
ControllerRenderProps
<
FormFields
,
Name
>
})
=>
React
.
ReactNode
;
rightElement
?:
({
field
}:
{
field
:
ControllerRenderProps
<
FormFields
,
Name
>
})
=>
React
.
ReactNode
;
inputProps
?:
HTMLChakraProps
<
'
input
'
|
'
textarea
'
>
;
inputProps
?:
InputProps
|
TextareaProps
;
}
}
ui/shared/monaco/CodeEditor.tsx
View file @
27872bfe
import
type
{
SystemStyleObject
}
from
'
@chakra-ui/react
'
;
import
type
{
SystemStyleObject
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
useColorMode
,
Flex
,
useToken
,
Center
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Flex
,
useToken
,
Center
}
from
'
@chakra-ui/react
'
;
import
type
{
EditorProps
}
from
'
@monaco-editor/react
'
;
import
type
{
EditorProps
}
from
'
@monaco-editor/react
'
;
import
MonacoEditor
from
'
@monaco-editor/react
'
;
import
MonacoEditor
from
'
@monaco-editor/react
'
;
import
type
*
as
monaco
from
'
monaco-editor/esm/vs/editor/editor.api
'
;
import
type
*
as
monaco
from
'
monaco-editor/esm/vs/editor/editor.api
'
;
...
@@ -11,6 +11,7 @@ import type { SmartContractExternalLibrary } from 'types/api/contract';
...
@@ -11,6 +11,7 @@ import type { SmartContractExternalLibrary } from 'types/api/contract';
import
useClientRect
from
'
lib/hooks/useClientRect
'
;
import
useClientRect
from
'
lib/hooks/useClientRect
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
isMetaKey
from
'
lib/isMetaKey
'
;
import
isMetaKey
from
'
lib/isMetaKey
'
;
import
{
useColorMode
}
from
'
toolkit/chakra/color-mode
'
;
import
ErrorBoundary
from
'
ui/shared/ErrorBoundary
'
;
import
ErrorBoundary
from
'
ui/shared/ErrorBoundary
'
;
import
CodeEditorBreadcrumbs
from
'
./CodeEditorBreadcrumbs
'
;
import
CodeEditorBreadcrumbs
from
'
./CodeEditorBreadcrumbs
'
;
...
@@ -56,7 +57,7 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
...
@@ -56,7 +57,7 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
const
[
containerRect
,
containerNodeRef
]
=
useClientRect
<
HTMLDivElement
>
();
const
[
containerRect
,
containerNodeRef
]
=
useClientRect
<
HTMLDivElement
>
();
const
{
colorMode
}
=
useColorMode
();
const
{
colorMode
}
=
useColorMode
();
const
borderRadius
=
useToken
(
'
radii
'
,
'
md
'
);
const
[
borderRadius
]
=
useToken
(
'
radii
'
,
'
md
'
);
const
isMobile
=
useIsMobile
();
const
isMobile
=
useIsMobile
();
const
themeColors
=
useThemeColors
();
const
themeColors
=
useThemeColors
();
...
@@ -202,28 +203,28 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
...
@@ -202,28 +203,28 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
setIsMetaPressed
(
false
);
setIsMetaPressed
(
false
);
},
[]);
},
[]);
const
container
Sx
:
SystemStyleObject
=
React
.
useMemo
(()
=>
({
const
container
Css
:
SystemStyleObject
=
React
.
useMemo
(()
=>
({
'
.editor-container
'
:
{
'
&
.editor-container
'
:
{
position
:
'
absolute
'
,
position
:
'
absolute
'
,
top
:
0
,
top
:
0
,
left
:
0
,
left
:
0
,
width
:
`
${
editorWidth
}
px`
,
width
:
`
${
editorWidth
}
px`
,
height
:
'
100%
'
,
height
:
'
100%
'
,
},
},
'
.monaco-editor
'
:
{
'
&
.monaco-editor
'
:
{
'
border-bottom-left-radius
'
:
borderRadius
,
'
border-bottom-left-radius
'
:
borderRadius
,
},
},
'
.monaco-editor .overflow-guard
'
:
{
'
&
.monaco-editor .overflow-guard
'
:
{
'
border-bottom-left-radius
'
:
borderRadius
,
'
border-bottom-left-radius
'
:
borderRadius
,
},
},
'
.monaco-editor .core-guide
'
:
{
'
&
.monaco-editor .core-guide
'
:
{
zIndex
:
1
,
zIndex
:
1
,
},
},
// '.monaco-editor .currentFindMatch': // TODO: find a better way to style this
// '.monaco-editor .currentFindMatch': // TODO: find a better way to style this
'
.monaco-editor .findMatch
'
:
{
'
&
.monaco-editor .findMatch
'
:
{
backgroundColor
:
themeColors
[
'
custom.findMatchHighlightBackground
'
],
backgroundColor
:
themeColors
[
'
custom.findMatchHighlightBackground
'
],
},
},
'
.highlight
'
:
{
'
&
.highlight
'
:
{
backgroundColor
:
themeColors
[
'
custom.findMatchHighlightBackground
'
],
backgroundColor
:
themeColors
[
'
custom.findMatchHighlightBackground
'
],
},
},
'
&&.meta-pressed .import-link:hover, &&.meta-pressed .import-link:hover + .import-link
'
:
{
'
&&.meta-pressed .import-link:hover, &&.meta-pressed .import-link:hover + .import-link
'
:
{
...
@@ -231,19 +232,19 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
...
@@ -231,19 +232,19 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
textDecoration
:
'
underline
'
,
textDecoration
:
'
underline
'
,
cursor
:
'
pointer
'
,
cursor
:
'
pointer
'
,
},
},
'
.risk-warning-primary
'
:
{
'
&
.risk-warning-primary
'
:
{
backgroundColor
:
themeColors
[
'
custom.riskWarning.primaryBackground
'
],
backgroundColor
:
themeColors
[
'
custom.riskWarning.primaryBackground
'
],
},
},
'
.risk-warning
'
:
{
'
&
.risk-warning
'
:
{
backgroundColor
:
themeColors
[
'
custom.riskWarning.background
'
],
backgroundColor
:
themeColors
[
'
custom.riskWarning.background
'
],
},
},
'
.main-contract-header
'
:
{
'
&
.main-contract-header
'
:
{
backgroundColor
:
themeColors
[
'
custom.mainContract.header
'
],
backgroundColor
:
themeColors
[
'
custom.mainContract.header
'
],
},
},
'
.main-contract-body
'
:
{
'
&
.main-contract-body
'
:
{
backgroundColor
:
themeColors
[
'
custom.mainContract.body
'
],
backgroundColor
:
themeColors
[
'
custom.mainContract.body
'
],
},
},
'
.main-contract-glyph
'
:
{
'
&
.main-contract-glyph
'
:
{
zIndex
:
1
,
zIndex
:
1
,
background
:
'
url(/static/contract_star.png) no-repeat center center
'
,
background
:
'
url(/static/contract_star.png) no-repeat center center
'
,
backgroundSize
:
'
12px
'
,
backgroundSize
:
'
12px
'
,
...
@@ -256,18 +257,18 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
...
@@ -256,18 +257,18 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
},
[
themeColors
]);
},
[
themeColors
]);
if
(
data
.
length
===
1
)
{
if
(
data
.
length
===
1
)
{
const
sx
=
{
const
css
=
{
...
container
Sx
,
...
container
Css
,
'
.monaco-editor
'
:
{
'
&
.monaco-editor
'
:
{
'
border-radius
'
:
borderRadius
,
'
border-radius
'
:
borderRadius
,
},
},
'
.monaco-editor .overflow-guard
'
:
{
'
&
.monaco-editor .overflow-guard
'
:
{
'
border-radius
'
:
borderRadius
,
'
border-radius
'
:
borderRadius
,
},
},
};
};
return
(
return
(
<
Box
height=
{
`${ EDITOR_HEIGHT }px`
}
width=
"100%"
sx=
{
sx
}
ref=
{
containerNodeRef
}
>
<
Box
height=
{
`${ EDITOR_HEIGHT }px`
}
width=
"100%"
css=
{
css
}
ref=
{
containerNodeRef
}
>
<
ErrorBoundary
renderErrorScreen=
{
renderErrorScreen
}
>
<
ErrorBoundary
renderErrorScreen=
{
renderErrorScreen
}
>
<
MonacoEditor
<
MonacoEditor
className=
"editor-container"
className=
"editor-container"
...
@@ -290,7 +291,7 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
...
@@ -290,7 +291,7 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractN
height=
{
`${ EDITOR_HEIGHT + TABS_HEIGHT + BREADCRUMBS_HEIGHT }px`
}
height=
{
`${ EDITOR_HEIGHT + TABS_HEIGHT + BREADCRUMBS_HEIGHT }px`
}
position=
"relative"
position=
"relative"
ref=
{
containerNodeRef
}
ref=
{
containerNodeRef
}
sx=
{
containerSx
}
css=
{
containerCss
}
overflow=
{
{
base
:
'
hidden
'
,
lg
:
'
visible
'
}
}
overflow=
{
{
base
:
'
hidden
'
,
lg
:
'
visible
'
}
}
borderRadius=
"md"
borderRadius=
"md"
onClick=
{
handleClick
}
onClick=
{
handleClick
}
...
...
ui/shared/monaco/CodeEditorFileTree.tsx
View file @
27872bfe
import
type
{
Chakra
Props
}
from
'
@chakra-ui/react
'
;
import
type
{
AccordionItem
Props
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Accordion
,
AccordionButton
,
AccordionItem
,
AccordionPanel
,
chakra
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
chakra
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
FileTree
}
from
'
./types
'
;
import
type
{
FileTree
}
from
'
./types
'
;
import
{
AccordionItem
,
AccordionItemContent
,
AccordionItemTrigger
,
AccordionRoot
}
from
'
toolkit/chakra/accordion
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
CodeEditorFileIcon
from
'
./CodeEditorFileIcon
'
;
import
CodeEditorFileIcon
from
'
./CodeEditorFileIcon
'
;
...
@@ -20,7 +21,13 @@ interface Props {
...
@@ -20,7 +21,13 @@ interface Props {
}
}
const
CodeEditorFileTree
=
({
tree
,
level
=
0
,
onItemClick
,
isCollapsed
,
selectedFile
,
mainFile
}:
Props
)
=>
{
const
CodeEditorFileTree
=
({
tree
,
level
=
0
,
onItemClick
,
isCollapsed
,
selectedFile
,
mainFile
}:
Props
)
=>
{
const
itemProps
:
ChakraProps
=
{
const
[
value
,
setValue
]
=
React
.
useState
<
Array
<
string
>>
(
isCollapsed
?
[]
:
tree
.
map
((
item
)
=>
item
.
name
));
const
handleValueChange
=
React
.
useCallback
(({
value
}:
{
value
:
Array
<
string
>
})
=>
{
setValue
(
value
);
},
[]);
const
itemProps
:
Partial
<
AccordionItemProps
>
=
{
borderWidth
:
'
0px
'
,
borderWidth
:
'
0px
'
,
cursor
:
'
pointer
'
,
cursor
:
'
pointer
'
,
lineHeight
:
'
22px
'
,
lineHeight
:
'
22px
'
,
...
@@ -31,47 +38,52 @@ const CodeEditorFileTree = ({ tree, level = 0, onItemClick, isCollapsed, selecte
...
@@ -31,47 +38,52 @@ const CodeEditorFileTree = ({ tree, level = 0, onItemClick, isCollapsed, selecte
const
themeColors
=
useThemeColors
();
const
themeColors
=
useThemeColors
();
return
(
return
(
<
Accordion
allowMultiple
defaultIndex=
{
isCollapsed
?
undefined
:
tree
.
map
((
item
,
index
)
=>
index
)
}
reduceMo
tion
>
<
Accordion
Root
multiple
value=
{
value
}
onValueChange=
{
handleValueChange
}
noAnima
tion
>
{
{
tree
.
map
((
leaf
,
index
)
=>
{
tree
.
map
((
leaf
,
index
)
=>
{
const
leafName
=
<
chakra
.
span
overflow=
"hidden"
textOverflow=
"ellipsis"
whiteSpace=
"nowrap"
>
{
leaf
.
name
}
</
chakra
.
span
>;
const
leafName
=
<
chakra
.
span
overflow=
"hidden"
textOverflow=
"ellipsis"
whiteSpace=
"nowrap"
>
{
leaf
.
name
}
</
chakra
.
span
>;
const
isExpanded
=
value
.
includes
(
leaf
.
name
);
if
(
'
children
'
in
leaf
)
{
if
(
'
children
'
in
leaf
)
{
return
(
return
(
<
AccordionItem
key=
{
index
}
{
...
itemProps
}
>
<
AccordionItem
key=
{
index
}
value=
{
leaf
.
name
}
{
...
itemProps
}
>
{
({
isExpanded
})
=>
(
<
AccordionItemTrigger
<>
pr=
"8px"
<
AccordionButton
py=
"0"
pr=
"8px"
pl=
{
`${ 8 + 8 * level }px`
}
py=
"0"
_hover=
{
{
bgColor
:
themeColors
[
'
custom.list.hoverBackground
'
]
}
}
pl=
{
`${ 8 + 8 * level }px`
}
fontSize=
"13px"
_hover=
{
{
bgColor
:
themeColors
[
'
custom.list.hoverBackground
'
]
}
}
lineHeight=
"22px"
fontSize=
"13px"
h=
"22px"
lineHeight=
"22px"
transitionDuration=
"0"
h=
"22px"
noIndicator
transitionDuration=
"0"
>
>
<
Box
<
Box
className=
"codicon codicon-tree-item-expanded"
className=
"codicon codicon-tree-item-expanded"
transform=
"rotate(-90deg)"
transform=
{
isExpanded
?
'
rotate(0deg)
'
:
'
rotate(-90deg)
'
}
_groupExpanded=
{
{
boxSize=
"16px"
transform
:
'
rotate(0deg)
'
,
mr=
"2px"
}
}
/>
boxSize=
"16px"
<
IconSvg
name=
{
isExpanded
?
'
monaco/folder-open
'
:
'
monaco/folder
'
}
boxSize=
"16px"
mr=
"4px"
/>
mr=
"2px"
{
leafName
}
/>
</
AccordionButton
>
<
IconSvg
<
AccordionPanel
p=
"0"
>
name=
{
isExpanded
?
'
monaco/folder-open
'
:
'
monaco/folder
'
}
<
CodeEditorFileTree
boxSize=
"16px"
tree=
{
leaf
.
children
}
mr=
"4px"
level=
{
level
+
1
}
/>
onItemClick=
{
onItemClick
}
{
leafName
}
isCollapsed=
{
isCollapsed
}
</
AccordionItemTrigger
>
selectedFile=
{
selectedFile
}
<
AccordionItemContent
p=
"0"
>
mainFile=
{
mainFile
}
<
CodeEditorFileTree
/>
tree=
{
leaf
.
children
}
</
AccordionPanel
>
level=
{
level
+
1
}
</>
onItemClick=
{
onItemClick
}
)
}
isCollapsed=
{
isCollapsed
}
selectedFile=
{
selectedFile
}
mainFile=
{
mainFile
}
/>
</
AccordionItemContent
>
</
AccordionItem
>
</
AccordionItem
>
);
);
}
}
...
@@ -79,6 +91,7 @@ const CodeEditorFileTree = ({ tree, level = 0, onItemClick, isCollapsed, selecte
...
@@ -79,6 +91,7 @@ const CodeEditorFileTree = ({ tree, level = 0, onItemClick, isCollapsed, selecte
return
(
return
(
<
AccordionItem
<
AccordionItem
key=
{
index
}
key=
{
index
}
value=
{
leaf
.
name
}
{
...
itemProps
}
{
...
itemProps
}
pl=
{
`${ 26 + (level * 8) }px`
}
pl=
{
`${ 26 + (level * 8) }px`
}
pr=
"8px"
pr=
"8px"
...
@@ -106,7 +119,7 @@ const CodeEditorFileTree = ({ tree, level = 0, onItemClick, isCollapsed, selecte
...
@@ -106,7 +119,7 @@ const CodeEditorFileTree = ({ tree, level = 0, onItemClick, isCollapsed, selecte
);
);
})
})
}
}
</
Accordion
>
</
Accordion
Root
>
);
);
};
};
...
...
ui/shared/monaco/CodeEditorMainFileIndicator.tsx
View file @
27872bfe
import
{
Box
,
chakra
,
Tooltip
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
chakra
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
Tooltip
}
from
'
toolkit/chakra/tooltip
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
interface
Props
{
interface
Props
{
...
@@ -9,7 +10,7 @@ interface Props {
...
@@ -9,7 +10,7 @@ interface Props {
const
CodeEditorMainFileIndicator
=
({
className
}:
Props
)
=>
{
const
CodeEditorMainFileIndicator
=
({
className
}:
Props
)
=>
{
return
(
return
(
<
Tooltip
label
=
"The main file containing verified contract"
>
<
Tooltip
content
=
"The main file containing verified contract"
>
<
Box
className=
{
className
}
>
<
Box
className=
{
className
}
>
<
IconSvg
name=
"star_filled"
boxSize=
{
3
}
display=
"block"
color=
"green.500"
/>
<
IconSvg
name=
"star_filled"
boxSize=
{
3
}
display=
"block"
color=
"green.500"
/>
</
Box
>
</
Box
>
...
...
ui/shared/monaco/CodeEditorSearch.tsx
View file @
27872bfe
import
type
{
ChakraProps
}
from
'
@chakra-ui/react
'
;
import
type
{
HTML
ChakraProps
}
from
'
@chakra-ui/react
'
;
import
{
Accordion
,
Box
,
Input
,
InputGroup
,
InputRightElement
,
useBoolean
}
from
'
@chakra-ui/react
'
;
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
type
*
as
monaco
from
'
monaco-editor/esm/vs/editor/editor.api
'
;
import
type
*
as
monaco
from
'
monaco-editor/esm/vs/editor/editor.api
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
File
,
Monaco
,
SearchResult
}
from
'
./types
'
;
import
type
{
File
,
Monaco
,
SearchResult
}
from
'
./types
'
;
import
useDebounce
from
'
lib/hooks/useDebounce
'
;
import
useDebounce
from
'
lib/hooks/useDebounce
'
;
import
{
AccordionRoot
}
from
'
toolkit/chakra/accordion
'
;
import
{
Input
}
from
'
toolkit/chakra/input
'
;
import
{
InputGroup
}
from
'
toolkit/chakra/input-group
'
;
import
CodeEditorSearchSection
from
'
./CodeEditorSearchSection
'
;
import
CodeEditorSearchSection
from
'
./CodeEditorSearchSection
'
;
import
CoderEditorCollapseButton
from
'
./CoderEditorCollapseButton
'
;
import
CoderEditorCollapseButton
from
'
./CoderEditorCollapseButton
'
;
...
@@ -24,16 +27,28 @@ interface Props {
...
@@ -24,16 +27,28 @@ interface Props {
const
CodeEditorSearch
=
({
monaco
,
data
,
onFileSelect
,
isInputStuck
,
isActive
,
setActionBarRenderer
,
defaultValue
}:
Props
)
=>
{
const
CodeEditorSearch
=
({
monaco
,
data
,
onFileSelect
,
isInputStuck
,
isActive
,
setActionBarRenderer
,
defaultValue
}:
Props
)
=>
{
const
[
searchTerm
,
changeSearchTerm
]
=
React
.
useState
(
''
);
const
[
searchTerm
,
changeSearchTerm
]
=
React
.
useState
(
''
);
const
[
searchResults
,
setSearchResults
]
=
React
.
useState
<
Array
<
SearchResult
>>
([]);
const
[
searchResults
,
setSearchResults
]
=
React
.
useState
<
Array
<
SearchResult
>>
([]);
const
[
expandedSections
,
setExpandedSections
]
=
React
.
useState
<
Array
<
number
>>
([]);
const
[
expandedSections
,
setExpandedSections
]
=
React
.
useState
<
Array
<
string
>>
([]);
const
[
isMatchCase
,
setMatchCase
]
=
useBoolean
(
);
const
[
isMatchCase
,
setMatchCase
]
=
React
.
useState
(
false
);
const
[
isMatchWholeWord
,
setMatchWholeWord
]
=
useBoolean
(
);
const
[
isMatchWholeWord
,
setMatchWholeWord
]
=
React
.
useState
(
false
);
const
[
isMatchRegex
,
setMatchRegex
]
=
useBoolean
(
);
const
[
isMatchRegex
,
setMatchRegex
]
=
React
.
useState
(
false
);
const
decorations
=
React
.
useRef
<
Record
<
string
,
Array
<
string
>>>
({});
const
decorations
=
React
.
useRef
<
Record
<
string
,
Array
<
string
>>>
({});
const
themeColors
=
useThemeColors
();
const
themeColors
=
useThemeColors
();
const
debouncedSearchTerm
=
useDebounce
(
searchTerm
,
300
);
const
debouncedSearchTerm
=
useDebounce
(
searchTerm
,
300
);
const
handleMatchCaseChange
=
React
.
useCallback
(()
=>
{
setMatchCase
((
prev
)
=>
!
prev
);
},
[]);
const
handleMatchWholeWordChange
=
React
.
useCallback
(()
=>
{
setMatchWholeWord
((
prev
)
=>
!
prev
);
},
[]);
const
handleMatchRegexChange
=
React
.
useCallback
(()
=>
{
setMatchRegex
((
prev
)
=>
!
prev
);
},
[]);
React
.
useEffect
(()
=>
{
React
.
useEffect
(()
=>
{
changeSearchTerm
(
defaultValue
);
changeSearchTerm
(
defaultValue
);
},
[
defaultValue
]);
},
[
defaultValue
]);
...
@@ -73,7 +88,7 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
...
@@ -73,7 +88,7 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
},
[
debouncedSearchTerm
,
isMatchCase
,
isMatchRegex
,
isMatchWholeWord
,
monaco
]);
},
[
debouncedSearchTerm
,
isMatchCase
,
isMatchRegex
,
isMatchWholeWord
,
monaco
]);
React
.
useEffect
(()
=>
{
React
.
useEffect
(()
=>
{
setExpandedSections
(
searchResults
.
map
((
item
,
index
)
=>
index
));
setExpandedSections
(
searchResults
.
map
((
item
)
=>
item
.
file_path
));
},
[
searchResults
]);
},
[
searchResults
]);
const
handleSearchTermChange
=
React
.
useCallback
((
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
handleSearchTermChange
=
React
.
useCallback
((
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
...
@@ -87,13 +102,13 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
...
@@ -87,13 +102,13 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
}
}
},
[
data
,
onFileSelect
]);
},
[
data
,
onFileSelect
]);
const
handleAccordionStateChange
=
React
.
useCallback
((
newValue
:
Array
<
number
>
)
=>
{
const
handleAccordionStateChange
=
React
.
useCallback
((
{
value
}:
{
value
:
Array
<
string
>
}
)
=>
{
setExpandedSections
(
newV
alue
);
setExpandedSections
(
v
alue
);
},
[]);
},
[]);
const
handleToggleCollapseClick
=
React
.
useCallback
(()
=>
{
const
handleToggleCollapseClick
=
React
.
useCallback
(()
=>
{
if
(
expandedSections
.
length
===
0
)
{
if
(
expandedSections
.
length
===
0
)
{
setExpandedSections
(
searchResults
.
map
((
item
,
index
)
=>
index
));
setExpandedSections
(
searchResults
.
map
((
item
)
=>
item
.
file_path
));
}
else
{
}
else
{
setExpandedSections
([]);
setExpandedSections
([]);
}
}
...
@@ -114,13 +129,14 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
...
@@ -114,13 +129,14 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
isActive
&&
setActionBarRenderer
(()
=>
renderActionBar
);
isActive
&&
setActionBarRenderer
(()
=>
renderActionBar
);
},
[
isActive
,
renderActionBar
,
setActionBarRenderer
]);
},
[
isActive
,
renderActionBar
,
setActionBarRenderer
]);
const
buttonProps
:
ChakraProps
=
{
const
buttonProps
:
HTMLChakraProps
<
'
div
'
>
=
{
boxSize
:
'
20px
'
,
boxSize
:
'
20px
'
,
p
:
'
1px
'
,
p
:
'
1px
'
,
cursor
:
'
pointer
'
,
cursor
:
'
pointer
'
,
borderRadius
:
'
3px
'
,
borderRadius
:
'
3px
'
,
borderWidth
:
'
1px
'
,
borderWidth
:
'
1px
'
,
borderColor
:
'
transparent
'
,
borderColor
:
'
transparent
'
,
color
:
'
global.body.fg
'
,
};
};
const
searchResultNum
=
(()
=>
{
const
searchResultNum
=
(()
=>
{
...
@@ -145,8 +161,40 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
...
@@ -145,8 +161,40 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
);
);
})();
})();
const
inputEndElement
=
(
<>
<
Box
{
...
buttonProps
}
className=
"codicon codicon-case-sensitive"
onClick=
{
handleMatchCaseChange
}
bgColor=
{
isMatchCase
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
'
transparent
'
}
_hover=
{
{
bgColor
:
isMatchCase
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
themeColors
[
'
custom.inputOption.hoverBackground
'
]
}
}
title=
"Match Case"
aria
-
label=
"Match Case"
/>
<
Box
{
...
buttonProps
}
className=
"codicon codicon-whole-word"
bgColor=
{
isMatchWholeWord
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
'
transparent
'
}
onClick=
{
handleMatchWholeWordChange
}
_hover=
{
{
bgColor
:
isMatchWholeWord
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
themeColors
[
'
custom.inputOption.hoverBackground
'
]
}
}
title=
"Match Whole Word"
aria
-
label=
"Match Whole Word"
/>
<
Box
{
...
buttonProps
}
className=
"codicon codicon-regex"
bgColor=
{
isMatchRegex
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
'
transparent
'
}
onClick=
{
handleMatchRegexChange
}
_hover=
{
{
bgColor
:
isMatchRegex
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
themeColors
[
'
custom.inputOption.hoverBackground
'
]
}
}
title=
"Use Regular Expression"
aria
-
label=
"Use Regular Expression"
/>
</>
);
return
(
return
(
<
Box
>
<>
<
InputGroup
<
InputGroup
px=
"8px"
px=
"8px"
position=
"sticky"
position=
"sticky"
...
@@ -155,17 +203,20 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
...
@@ -155,17 +203,20 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
zIndex=
"2"
zIndex=
"2"
bgColor=
{
themeColors
[
'
sideBar.background
'
]
}
bgColor=
{
themeColors
[
'
sideBar.background
'
]
}
pb=
"8px"
pb=
"8px"
boxShadow=
{
isInputStuck
?
'
md
'
:
'
none
'
}
boxShadow=
{
isInputStuck
?
'
0px 6px 3px 0px rgba(0, 0, 0, 0.05)
'
:
'
none
'
}
endElement=
{
inputEndElement
}
endElementProps=
{
{
height
:
'
26px
'
,
pl
:
'
0
'
,
pr
:
'
10px
'
,
columnGap
:
'
2px
'
}
}
endOffset=
"75px"
>
>
<
Input
<
Input
size=
"xs"
size=
"xs"
onChange=
{
handleSearchTermChange
}
onChange=
{
handleSearchTermChange
}
value=
{
searchTerm
}
value=
{
searchTerm
}
placeholder=
"Search"
placeholder=
"Search"
variant=
"unstyled"
color=
{
themeColors
[
'
input.foreground
'
]
}
color=
{
themeColors
[
'
input.foreground
'
]
}
bgColor=
{
themeColors
[
'
input.background
'
]
}
bgColor=
{
themeColors
[
'
input.background
'
]
}
borderRadius=
"none"
borderRadius=
"none"
height=
"26px"
fontSize=
"13px"
fontSize=
"13px"
lineHeight=
"20px"
lineHeight=
"20px"
borderWidth=
"1px"
borderWidth=
"1px"
...
@@ -178,47 +229,19 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
...
@@ -178,47 +229,19 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
borderColor
:
themeColors
.
focusBorder
,
borderColor
:
themeColors
.
focusBorder
,
}
}
}
}
/>
/>
<
InputRightElement
w=
"auto"
h=
"auto"
right=
"12px"
top=
"3px"
columnGap=
"2px"
>
<
Box
{
...
buttonProps
}
className=
"codicon codicon-case-sensitive"
onClick=
{
setMatchCase
.
toggle
}
bgColor=
{
isMatchCase
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
'
transparent
'
}
_hover=
{
{
bgColor
:
isMatchCase
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
themeColors
[
'
custom.inputOption.hoverBackground
'
]
}
}
title=
"Match Case"
aria
-
label=
"Match Case"
/>
<
Box
{
...
buttonProps
}
className=
"codicon codicon-whole-word"
bgColor=
{
isMatchWholeWord
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
'
transparent
'
}
onClick=
{
setMatchWholeWord
.
toggle
}
_hover=
{
{
bgColor
:
isMatchWholeWord
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
themeColors
[
'
custom.inputOption.hoverBackground
'
]
}
}
title=
"Match Whole Word"
aria
-
label=
"Match Whole Word"
/>
<
Box
{
...
buttonProps
}
className=
"codicon codicon-regex"
bgColor=
{
isMatchRegex
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
'
transparent
'
}
onClick=
{
setMatchRegex
.
toggle
}
_hover=
{
{
bgColor
:
isMatchRegex
?
themeColors
[
'
custom.inputOption.activeBackground
'
]
:
themeColors
[
'
custom.inputOption.hoverBackground
'
]
}
}
title=
"Use Regular Expression"
aria
-
label=
"Use Regular Expression"
/>
</
InputRightElement
>
</
InputGroup
>
</
InputGroup
>
{
searchResultNum
}
{
searchResultNum
}
<
Accordion
<
Accordion
Root
key=
{
debouncedSearchTerm
}
key=
{
debouncedSearchTerm
}
allowM
ultiple
m
ultiple
index
=
{
expandedSections
}
value
=
{
expandedSections
}
onChange=
{
handleAccordionStateChange
}
on
Value
Change=
{
handleAccordionStateChange
}
reduceMo
tion
noAnima
tion
>
>
{
searchResults
.
map
((
item
)
=>
<
CodeEditorSearchSection
key=
{
item
.
file_path
}
data=
{
item
}
onItemClick=
{
handleResultItemClick
}
/>)
}
{
searchResults
.
map
((
item
)
=>
<
CodeEditorSearchSection
key=
{
item
.
file_path
}
data=
{
item
}
onItemClick=
{
handleResultItemClick
}
/>)
}
</
Accordion
>
</
Accordion
Root
>
</
Box
>
</>
);
);
};
};
...
...
ui/shared/monaco/CodeEditorSearchSection.tsx
View file @
27872bfe
import
{
AccordionButton
,
AccordionItem
,
AccordionPanel
,
Box
}
from
'
@chakra-ui/react
'
;
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
SearchResult
}
from
'
./types
'
;
import
type
{
SearchResult
}
from
'
./types
'
;
import
{
AccordionItem
,
AccordionItemContent
,
AccordionItemTrigger
}
from
'
toolkit/chakra/accordion
'
;
import
CodeEditorFileIcon
from
'
./CodeEditorFileIcon
'
;
import
CodeEditorFileIcon
from
'
./CodeEditorFileIcon
'
;
import
CodeEditorSearchResultItem
from
'
./CodeEditorSearchResultItem
'
;
import
CodeEditorSearchResultItem
from
'
./CodeEditorSearchResultItem
'
;
import
getFileName
from
'
./utils/getFileName
'
;
import
getFileName
from
'
./utils/getFileName
'
;
...
@@ -26,58 +28,59 @@ const CodeEditorSearchSection = ({ data, onItemClick }: Props) => {
...
@@ -26,58 +28,59 @@ const CodeEditorSearchSection = ({ data, onItemClick }: Props) => {
const
themeColors
=
useThemeColors
();
const
themeColors
=
useThemeColors
();
return
(
return
(
<
AccordionItem
borderWidth=
"0px"
_last=
{
{
borderBottomWidth
:
'
0px
'
}
}
>
<
AccordionItem
value=
{
data
.
file_path
}
borderWidth=
"0px"
_last=
{
{
borderBottomWidth
:
'
0px
'
}
}
>
{
({
isExpanded
})
=>
(
<
AccordionItemTrigger
<>
py=
{
0
}
<
AccordionButton
px=
{
2
}
py=
{
0
}
_hover=
{
{
bgColor
:
themeColors
[
'
custom.list.hoverBackground
'
]
}
}
px=
{
2
}
fontSize=
"13px"
_hover=
{
{
bgColor
:
themeColors
[
'
custom.list.hoverBackground
'
]
}
}
transitionDuration=
"0"
fontSize=
"13px"
lineHeight=
"22px"
transitionDuration=
"0"
alignItems=
"center"
lineHeight=
"22px"
noIndicator
alignItems=
"center"
>
>
<
Box
<
Box
className=
"codicon codicon-tree-item-expanded"
className=
"codicon codicon-tree-item-expanded"
transform=
"rotate(-90deg)"
transform=
{
isExpanded
?
'
rotate(0deg)
'
:
'
rotate(-90deg)
'
}
_groupExpanded=
{
{
width=
"20px"
transform
:
'
rotate(0deg)
'
,
height=
"22px"
}
}
py=
"3px"
// transform={ isExpanded ? 'rotate(0deg)' : 'rotate(-90deg)' }
flexShrink=
{
0
}
width=
"20px"
/>
height=
"22px"
<
CodeEditorFileIcon
mr=
"4px"
fileName=
{
fileName
}
/>
py=
"3px"
<
Box
flexShrink=
{
0
}
mr=
"8px"
/>
whiteSpace=
"nowrap"
<
CodeEditorFileIcon
mr=
"4px"
fileName=
{
fileName
}
/>
overflow=
"hidden"
<
Box
textOverflow=
"ellipsis"
mr=
"8px"
textAlign=
"left"
whiteSpace=
"nowrap"
>
overflow=
"hidden"
{
fileName
}
textOverflow=
"ellipsis"
</
Box
>
textAlign=
"left"
<
Box
>
className=
"monaco-count-badge"
{
fileName
}
ml=
"auto"
</
Box
>
bgColor=
{
themeColors
[
'
badge.background
'
]
}
<
Box
flexShrink=
{
0
}
className=
"monaco-count-badge"
>
ml=
"auto"
{
data
.
matches
.
length
}
bgColor=
{
themeColors
[
'
badge.background
'
]
}
</
Box
>
flexShrink=
{
0
}
</
AccordionButton
>
>
<
AccordionPanel
p=
{
0
}
>
{
data
.
matches
.
length
}
{
data
.
matches
.
map
((
match
)
=>
(
</
Box
>
<
CodeEditorSearchResultItem
</
AccordionItemTrigger
>
key=
{
data
.
file_path
+
'
_
'
+
match
.
startLineNumber
+
'
_
'
+
match
.
startColumn
}
<
AccordionItemContent
p=
{
0
}
>
filePath=
{
data
.
file_path
}
{
data
.
matches
.
map
((
match
)
=>
(
onClick=
{
handleFileLineClick
}
<
CodeEditorSearchResultItem
{
...
match
}
key=
{
data
.
file_path
+
'
_
'
+
match
.
startLineNumber
+
'
_
'
+
match
.
startColumn
}
/>
filePath=
{
data
.
file_path
}
),
onClick=
{
handleFileLineClick
}
)
}
{
...
match
}
</
AccordionPanel
>
/>
</>
),
)
}
)
}
</
AccordionItemContent
>
</
AccordionItem
>
</
AccordionItem
>
);
);
};
};
...
...
ui/shared/monaco/CodeEditorSideBar.tsx
View file @
27872bfe
import
type
{
HTMLChakraProps
}
from
'
@chakra-ui/react
'
;
import
{
Box
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Tab
,
TabList
,
TabPanel
,
TabPanels
,
Tabs
,
useBoolean
}
from
'
@chakra-ui/react
'
;
import
{
throttle
}
from
'
es-toolkit
'
;
import
{
throttle
}
from
'
es-toolkit
'
;
import
type
*
as
monaco
from
'
monaco-editor/esm/vs/editor/editor.api
'
;
import
type
*
as
monaco
from
'
monaco-editor/esm/vs/editor/editor.api
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
...
@@ -7,6 +6,8 @@ import React from 'react';
...
@@ -7,6 +6,8 @@ import React from 'react';
import
type
{
File
,
Monaco
}
from
'
./types
'
;
import
type
{
File
,
Monaco
}
from
'
./types
'
;
import
{
shift
,
cmd
}
from
'
lib/html-entities
'
;
import
{
shift
,
cmd
}
from
'
lib/html-entities
'
;
import
type
{
TabsTriggerProps
}
from
'
toolkit/chakra/tabs
'
;
import
{
TabsContent
,
TabsList
,
TabsRoot
,
TabsTrigger
}
from
'
toolkit/chakra/tabs
'
;
import
CodeEditorFileExplorer
from
'
./CodeEditorFileExplorer
'
;
import
CodeEditorFileExplorer
from
'
./CodeEditorFileExplorer
'
;
import
CodeEditorSearch
from
'
./CodeEditorSearch
'
;
import
CodeEditorSearch
from
'
./CodeEditorSearch
'
;
...
@@ -26,14 +27,14 @@ export const CONTAINER_WIDTH = 250;
...
@@ -26,14 +27,14 @@ export const CONTAINER_WIDTH = 250;
const
CodeEditorSideBar
=
({
onFileSelect
,
data
,
monaco
,
editor
,
selectedFile
,
mainFile
}:
Props
)
=>
{
const
CodeEditorSideBar
=
({
onFileSelect
,
data
,
monaco
,
editor
,
selectedFile
,
mainFile
}:
Props
)
=>
{
const
[
isStuck
,
setIsStuck
]
=
React
.
useState
(
false
);
const
[
isStuck
,
setIsStuck
]
=
React
.
useState
(
false
);
const
[
isDrawerOpen
,
setIsDrawerOpen
]
=
useBoolean
(
false
);
const
[
isDrawerOpen
,
setIsDrawerOpen
]
=
React
.
useState
(
false
);
const
[
tabIndex
,
setTabIndex
]
=
React
.
useState
(
0
);
const
[
activeTab
,
setActiveTab
]
=
React
.
useState
(
'
explorer
'
);
const
[
searchValue
,
setSearchValue
]
=
React
.
useState
(
''
);
const
[
searchValue
,
setSearchValue
]
=
React
.
useState
(
''
);
const
[
actionBarRenderer
,
setActionBarRenderer
]
=
React
.
useState
<
()
=>
React
.
JSX
.
Element
>
();
const
[
actionBarRenderer
,
setActionBarRenderer
]
=
React
.
useState
<
()
=>
React
.
JSX
.
Element
>
();
const
themeColors
=
useThemeColors
();
const
themeColors
=
useThemeColors
();
const
tabProps
:
HTMLChakraProps
<
'
button
'
>
=
{
const
tabProps
:
Partial
<
TabsTriggerProps
>
=
{
fontFamily
:
'
heading
'
,
fontFamily
:
'
heading
'
,
textTransform
:
'
uppercase
'
,
textTransform
:
'
uppercase
'
,
fontSize
:
'
11px
'
,
fontSize
:
'
11px
'
,
...
@@ -52,10 +53,18 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
...
@@ -52,10 +53,18 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
},
100
));
},
100
));
const
handleFileSelect
=
React
.
useCallback
((
index
:
number
,
lineNumber
?:
number
)
=>
{
const
handleFileSelect
=
React
.
useCallback
((
index
:
number
,
lineNumber
?:
number
)
=>
{
isDrawerOpen
&&
setIsDrawerOpen
.
off
(
);
isDrawerOpen
&&
setIsDrawerOpen
(
false
);
onFileSelect
(
index
,
lineNumber
);
onFileSelect
(
index
,
lineNumber
);
},
[
isDrawerOpen
,
onFileSelect
,
setIsDrawerOpen
]);
},
[
isDrawerOpen
,
onFileSelect
,
setIsDrawerOpen
]);
const
handleSideBarButtonClick
=
React
.
useCallback
(()
=>
{
setIsDrawerOpen
((
prev
)
=>
!
prev
);
},
[]);
const
handleTabChange
=
React
.
useCallback
(({
value
}:
{
value
:
string
})
=>
{
setActiveTab
(
value
);
},
[]);
React
.
useEffect
(()
=>
{
React
.
useEffect
(()
=>
{
if
(
editor
&&
monaco
)
{
if
(
editor
&&
monaco
)
{
editor
.
addAction
({
editor
.
addAction
({
...
@@ -67,7 +76,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
...
@@ -67,7 +76,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
contextMenuGroupId
:
'
navigation
'
,
contextMenuGroupId
:
'
navigation
'
,
contextMenuOrder
:
1.5
,
contextMenuOrder
:
1.5
,
run
:
function
()
{
run
:
function
()
{
set
TabIndex
(
0
);
set
ActiveTab
(
'
explorer
'
);
},
},
});
});
...
@@ -80,7 +89,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
...
@@ -80,7 +89,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
contextMenuGroupId
:
'
navigation
'
,
contextMenuGroupId
:
'
navigation
'
,
contextMenuOrder
:
1.6
,
contextMenuOrder
:
1.6
,
run
:
function
(
editor
)
{
run
:
function
(
editor
)
{
set
TabIndex
(
1
);
set
ActiveTab
(
'
search
'
);
const
selection
=
editor
.
getSelection
();
const
selection
=
editor
.
getSelection
();
const
selectedValue
=
selection
?
editor
.
getModel
()?.
getValueInRange
(
selection
)
:
''
;
const
selectedValue
=
selection
?
editor
.
getModel
()?.
getValueInRange
(
selection
)
:
''
;
setSearchValue
(
selectedValue
||
''
);
setSearchValue
(
selectedValue
||
''
);
...
@@ -111,8 +120,8 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
...
@@ -111,8 +120,8 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
borderTopRightRadius=
"md"
borderTopRightRadius=
"md"
borderBottomRightRadius=
"md"
borderBottomRightRadius=
"md"
>
>
<
Tabs
isLazy
lazyBehavior=
"keepMounted"
variant=
"unstyled"
size=
"13px"
index=
{
tabIndex
}
onChange=
{
setTabIndex
}
>
<
Tabs
Root
unmountOnExit=
{
false
}
variant=
"unstyled"
size=
"free"
value=
{
activeTab
}
onValueChange=
{
handleTabChange
}
>
<
TabList
<
Tab
s
List
columnGap=
{
3
}
columnGap=
{
3
}
position=
"sticky"
position=
"sticky"
top=
{
0
}
top=
{
0
}
...
@@ -120,37 +129,37 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
...
@@ -120,37 +129,37 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
bgColor=
{
themeColors
[
'
sideBar.background
'
]
}
bgColor=
{
themeColors
[
'
sideBar.background
'
]
}
zIndex=
"1"
zIndex=
"1"
px=
{
2
}
px=
{
2
}
h=
"35px"
alignItems=
"center"
boxShadow=
{
isStuck
?
'
md
'
:
'
none
'
}
boxShadow=
{
isStuck
?
'
md
'
:
'
none
'
}
borderTopRightRadius=
"md"
borderTopRightRadius=
"md"
>
>
<
Tab
{
...
tabProps
}
title=
{
`File explorer (${ shift + cmd }E)`
}
>
Explorer
</
Tab
>
<
Tab
sTrigger
value=
"explorer"
{
...
tabProps
}
title=
{
`File explorer (${ shift + cmd }E)`
}
>
Explorer
</
TabsTrigger
>
<
Tab
{
...
tabProps
}
title=
{
`Search in files (${ shift + cmd }F)`
}
>
Search
</
Tab
>
<
Tab
sTrigger
value=
"search"
{
...
tabProps
}
title=
{
`Search in files (${ shift + cmd }F)`
}
>
Search
</
TabsTrigger
>
{
actionBarRenderer
?.()
}
{
actionBarRenderer
?.()
}
</
TabList
>
</
TabsList
>
<
TabPanels
>
<
TabsContent
value=
"explorer"
p=
{
0
}
>
<
TabPanel
p=
{
0
}
>
<
CodeEditorFileExplorer
<
CodeEditorFileExplorer
data=
{
data
}
data=
{
data
}
onFileSelect=
{
handleFileSelect
}
onFileSelect=
{
handleFileSelect
}
selectedFile=
{
selectedFile
}
selectedFile=
{
selectedFile
}
mainFile=
{
mainFile
}
mainFile=
{
mainFile
}
isActive=
{
activeTab
===
'
explorer
'
}
isActive=
{
tabIndex
===
0
}
setActionBarRenderer=
{
setActionBarRenderer
}
setActionBarRenderer=
{
setActionBarRenderer
}
/>
/>
</
TabsContent
>
</
TabPanel
>
<
TabsContent
value=
"search"
p=
{
0
}
>
<
TabPanel
p=
{
0
}
>
<
CodeEditorSearch
<
CodeEditorSearch
data=
{
data
}
data=
{
data
}
onFileSelect=
{
handleFileSelect
}
onFileSelect=
{
handleFileSelect
}
monaco=
{
monaco
}
monaco=
{
monaco
}
isInputStuck=
{
isStuck
}
isInputStuck=
{
isStuck
}
isActive=
{
activeTab
===
'
search
'
}
isActive=
{
tabIndex
===
1
}
setActionBarRenderer=
{
setActionBarRenderer
}
setActionBarRenderer=
{
setActionBarRenderer
}
defaultValue=
{
searchValue
}
defaultValue=
{
searchValue
}
/>
/>
</
TabsContent
>
</
TabPanel
>
</
TabsRoot
>
</
TabPanels
>
</
Tabs
>
</
Box
>
</
Box
>
<
Box
<
Box
boxSize=
"24px"
boxSize=
"24px"
...
@@ -163,7 +172,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
...
@@ -163,7 +172,7 @@ const CodeEditorSideBar = ({ onFileSelect, data, monaco, editor, selectedFile, m
borderTopLeftRadius=
"4px"
borderTopLeftRadius=
"4px"
borderBottomLeftRadius=
"4px"
borderBottomLeftRadius=
"4px"
boxShadow=
"md"
boxShadow=
"md"
onClick=
{
setIsDrawerOpen
.
toggle
}
onClick=
{
handleSideBarButtonClick
}
zIndex=
"1"
zIndex=
"1"
transitionProperty=
"right"
transitionProperty=
"right"
transitionDuration=
"normal"
transitionDuration=
"normal"
...
...
ui/shared/monaco/CodeEditorTab.tsx
View file @
27872bfe
...
@@ -48,7 +48,7 @@ const CodeEditorTab = ({ isActive, isMainFile, path, onClick, onClose, isCloseDi
...
@@ -48,7 +48,7 @@ const CodeEditorTab = ({ isActive, isMainFile, path, onClick, onClose, isCloseDi
cursor=
"pointer"
cursor=
"pointer"
onClick=
{
handleClick
}
onClick=
{
handleClick
}
_hover=
{
{
_hover=
{
{
'
.codicon-close
'
:
{
'
&
.codicon-close
'
:
{
visibility
:
'
visible
'
,
visibility
:
'
visible
'
,
},
},
}
}
}
}
...
...
ui/shared/monaco/utils/themes.ts
View file @
27872bfe
export
const
light
=
{
import
type
*
as
monaco
from
'
monaco-editor/esm/vs/editor/editor.api
'
;
export
const
light
:
monaco
.
editor
.
IStandaloneThemeData
=
{
base
:
'
vs
'
as
const
,
base
:
'
vs
'
as
const
,
inherit
:
true
,
inherit
:
true
,
rules
:
[
rules
:
[
...
@@ -44,7 +46,7 @@ export const light = {
...
@@ -44,7 +46,7 @@ export const light = {
}
as
const
,
}
as
const
,
};
};
export
const
dark
=
{
export
const
dark
:
monaco
.
editor
.
IStandaloneThemeData
=
{
base
:
'
vs-dark
'
as
const
,
base
:
'
vs-dark
'
as
const
,
inherit
:
true
,
inherit
:
true
,
rules
:
[
rules
:
[
...
...
ui/shared/monaco/utils/useThemeColors.ts
View file @
27872bfe
import
{
useColorModeValue
}
from
'
@chakra-ui/react
'
;
import
{
useColorModeValue
}
from
'
toolkit/chakra/color-mode
'
;
import
*
as
themes
from
'
./themes
'
;
import
*
as
themes
from
'
./themes
'
;
...
...
ui/showcases/Tabs.tsx
View file @
27872bfe
...
@@ -41,6 +41,18 @@ const TabsShowcase = () => {
...
@@ -41,6 +41,18 @@ const TabsShowcase = () => {
<
TabsContent
value=
"tab2"
>
Second tab content
</
TabsContent
>
<
TabsContent
value=
"tab2"
>
Second tab content
</
TabsContent
>
</
TabsRoot
>
</
TabsRoot
>
</
Sample
>
</
Sample
>
<
Sample
label=
"variant: segmented"
>
<
TabsRoot
defaultValue=
"tab1"
variant=
"segmented"
size=
"sm"
>
<
TabsList
>
<
TabsTrigger
value=
"tab1"
>
First tab
</
TabsTrigger
>
<
TabsTrigger
value=
"tab2"
>
Second tab
</
TabsTrigger
>
<
TabsTrigger
value=
"tab3"
>
Third tab
</
TabsTrigger
>
</
TabsList
>
<
TabsContent
value=
"tab1"
>
First tab content
</
TabsContent
>
<
TabsContent
value=
"tab2"
>
Second tab content
</
TabsContent
>
<
TabsContent
value=
"tab3"
>
Third tab content
</
TabsContent
>
</
TabsRoot
>
</
Sample
>
</
SamplesStack
>
</
SamplesStack
>
</
Section
>
</
Section
>
...
...
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