Merge pull request #1671 from ethereum/vertical-icons-panel-react
create vertical icons panel react libpull/1849/head
commit
32a322bad7
@ -0,0 +1,4 @@ |
||||
{ |
||||
"presets": ["@nrwl/react/babel"], |
||||
"plugins": [] |
||||
} |
@ -0,0 +1,19 @@ |
||||
{ |
||||
"env": { |
||||
"browser": true, |
||||
"es6": true |
||||
}, |
||||
"extends": ["../../../.eslintrc"], |
||||
"globals": { |
||||
"Atomics": "readonly", |
||||
"SharedArrayBuffer": "readonly" |
||||
}, |
||||
"parserOptions": { |
||||
"ecmaVersion": 11, |
||||
"sourceType": "module" |
||||
}, |
||||
"rules": { |
||||
"no-unused-vars": "off", |
||||
"@typescript-eslint/no-unused-vars": "error" |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
{ |
||||
"tabWidth": 2, |
||||
"singleQuote": true, |
||||
"semi": false |
||||
} |
@ -0,0 +1,7 @@ |
||||
# remix-ui-vertical-icons-panel |
||||
|
||||
React library for RemixIde vertical icons Panel |
||||
|
||||
## Running unit tests |
||||
|
||||
Run `nx test remix-ui-vertical-icons-panel` to execute the unit tests via [Jest](https://jestjs.io). |
@ -0,0 +1 @@ |
||||
export * from './lib/remix-ui-vertical-icons-panel' |
@ -0,0 +1,68 @@ |
||||
/* eslint-disable @typescript-eslint/no-unused-vars */ |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import React, { Fragment, useEffect, useReducer } from 'react' |
||||
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer' |
||||
import { BadgeStatus, IconProfile, IconStatus } from './Icon' |
||||
|
||||
interface BadgeProps { |
||||
badgeStatus: BadgeStatus |
||||
} |
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function Badge ({ badgeStatus }: BadgeProps) { |
||||
/** |
||||
* resolve a classes list for @arg key |
||||
* @param {Object} key |
||||
* @param {Object} type |
||||
*/ |
||||
function resolveClasses (key: string, type: string) { |
||||
let classes = 'remixui_status' |
||||
switch (key) { |
||||
case 'succeed': |
||||
classes += ' fas fa-check-circle text-' + type + ' ' + 'remixui_statusCheck' |
||||
break |
||||
case 'edited': |
||||
classes += ' fas fa-sync text-' + type + ' ' + 'remixui_statusCheck' |
||||
break |
||||
case 'loading': |
||||
classes += ' fas fa-spinner text-' + type + ' ' + 'remixui_statusCheck' |
||||
break |
||||
case 'failed': |
||||
classes += ' fas fa-exclamation-triangle text-' + type + ' ' + 'remixui_statusCheck' |
||||
break |
||||
default: { |
||||
classes += ' badge badge-pill badge-' + type |
||||
} |
||||
} |
||||
return classes |
||||
} |
||||
|
||||
function checkStatusKeyValue (value: any, type: string) { |
||||
if (value === 'succeed' || value === 'edited' || value === 'loading' || value === 'failed' || |
||||
typeof value === 'number' || type === 'warning' || type === 'error' || type === 'success' || type === 'info' || type === 'danger') { |
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
return ( |
||||
<> |
||||
{ |
||||
badgeStatus && checkStatusKeyValue(badgeStatus.key, badgeStatus.type) ? ( |
||||
<i |
||||
title={badgeStatus.title} |
||||
className={resolveClasses(badgeStatus.key, badgeStatus.type!)} |
||||
aria-hidden="true" |
||||
> |
||||
{badgeStatus.text} |
||||
</i> |
||||
) : null |
||||
} |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export default Badge |
@ -0,0 +1,14 @@ |
||||
/* eslint-disable no-use-before-define */ |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import React from 'react' |
||||
|
||||
function BasicLogo () { |
||||
return (<svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 100"> |
||||
<path d="M91.84,35a.09.09,0,0,1-.1-.07,41,41,0,0,0-79.48,0,.09.09,0,0,1-.1.07C9.45,35,1,35.35,1,42.53c0,8.56,1,16,6,20.32,2.16,1.85,5.81,2.3,9.27,2.22a44.4,44.4,0,0,0,6.45-.68.09.09,0,0,0,.06-.15A34.81,34.81,0,0,1,17,45c0-.1,0-.21,0-.31a35,35,0,0,1,70,0c0,.1,0,.21,0,.31a34.81,34.81,0,0,1-5.78,19.24.09.09,0,0,0,.06.15,44.4,44.4,0,0,0,6.45.68c3.46.08,7.11-.37,9.27-2.22,5-4.27,6-11.76,6-20.32C103,35.35,94.55,35,91.84,35Z"/> |
||||
<path d="M52,74,25.4,65.13a.1.1,0,0,0-.1.17L51.93,91.93a.1.1,0,0,0,.14,0L78.7,65.3a.1.1,0,0,0-.1-.17L52,74A.06.06,0,0,1,52,74Z"/> |
||||
<path d="M75.68,46.9,82,45a.09.09,0,0,0,.08-.09,29.91,29.91,0,0,0-.87-6.94.11.11,0,0,0-.09-.08l-6.43-.58a.1.1,0,0,1-.06-.18l4.78-4.18a.13.13,0,0,0,0-.12,30.19,30.19,0,0,0-3.65-6.07.09.09,0,0,0-.11,0l-5.91,2a.1.1,0,0,1-.12-.14L72.19,23a.11.11,0,0,0,0-.12,29.86,29.86,0,0,0-5.84-4.13.09.09,0,0,0-.11,0l-4.47,4.13a.1.1,0,0,1-.17-.07l.09-6a.1.1,0,0,0-.07-.1,30.54,30.54,0,0,0-7-1.47.1.1,0,0,0-.1.07l-2.38,5.54a.1.1,0,0,1-.18,0l-2.37-5.54a.11.11,0,0,0-.11-.06,30,30,0,0,0-7,1.48.12.12,0,0,0-.07.1l.08,6.05a.09.09,0,0,1-.16.07L37.8,18.76a.11.11,0,0,0-.12,0,29.75,29.75,0,0,0-5.83,4.13.11.11,0,0,0,0,.12l2.59,5.6a.11.11,0,0,1-.13.14l-5.9-2a.11.11,0,0,0-.12,0,30.23,30.23,0,0,0-3.62,6.08.11.11,0,0,0,0,.12l4.79,4.19a.1.1,0,0,1-.06.17L23,37.91a.1.1,0,0,0-.09.07A29.9,29.9,0,0,0,22,44.92a.1.1,0,0,0,.07.1L28.4,47a.1.1,0,0,1,0,.18l-5.84,3.26a.16.16,0,0,0,0,.11,30.17,30.17,0,0,0,2.1,6.76c.32.71.67,1.4,1,2.08a.1.1,0,0,0,.06,0L52,68.16H52l26.34-8.78a.1.1,0,0,0,.06-.05,30.48,30.48,0,0,0,3.11-8.88.1.1,0,0,0-.05-.11l-5.83-3.26A.1.1,0,0,1,75.68,46.9Z"/> |
||||
</svg> |
||||
) |
||||
} |
||||
|
||||
export default BasicLogo |
@ -0,0 +1,18 @@ |
||||
/* eslint-disable no-use-before-define */ |
||||
import React, { MutableRefObject } from 'react' |
||||
|
||||
export interface ChevronProps { |
||||
divElementRef: MutableRefObject<any> |
||||
cssRule: string |
||||
} |
||||
|
||||
function Chevron (props: ChevronProps) { |
||||
return ( |
||||
<> |
||||
{ props.divElementRef.current && props.divElementRef.current.scrollHeight > props.divElementRef.current.clientHeight |
||||
? <i className={props.cssRule}></i> : null } |
||||
</> |
||||
) |
||||
} |
||||
|
||||
export { Chevron } |
@ -0,0 +1,62 @@ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import React, { Fragment, useEffect, useReducer } from 'react' |
||||
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer' |
||||
import Badge from './Badge' |
||||
import Icon, { IconStatus } from './Icon' |
||||
|
||||
interface DebuggerProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
} |
||||
|
||||
const initialState = { |
||||
text: '', |
||||
key: '', |
||||
title: '', |
||||
type: '' |
||||
} |
||||
|
||||
function Debugger ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: DebuggerProps) { |
||||
const [badgeStatus, dispatchStatusUpdate] = useReducer(iconBadgeReducer, initialState) |
||||
|
||||
useEffect(() => { |
||||
verticalIconsPlugin.on('debugger', 'statusChanged', (iconStatus: IconStatus) => { |
||||
const action: IconBadgeReducerAction = { type: 'debugger', payload: { status: iconStatus, verticalIconPlugin: verticalIconsPlugin } } |
||||
dispatchStatusUpdate(action) |
||||
}) |
||||
}, []) |
||||
|
||||
return ( |
||||
<Fragment> |
||||
{verticalIconsPlugin.targetProfileForChange && |
||||
Object.keys(verticalIconsPlugin.targetProfileForChange).length |
||||
? Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(p => p === 'debugger') |
||||
.map(p => ( |
||||
<div id="debuggingIcons" data-id="verticalIconsDebuggingIcons" key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
}> |
||||
<Icon |
||||
profile={verticalIconsPlugin.targetProfileForChange[p]} |
||||
verticalIconPlugin={verticalIconsPlugin} |
||||
contextMenuAction={itemContextAction} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
} |
||||
/> |
||||
<Badge |
||||
badgeStatus={badgeStatus} |
||||
/> |
||||
</div> |
||||
)) |
||||
: null} |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export default Debugger |
@ -0,0 +1,59 @@ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import React, { Fragment, useEffect, useRef } from 'react' |
||||
import Icon from './Icon' |
||||
|
||||
interface FilePanelProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
} |
||||
|
||||
function FilePanel ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: FilePanelProps) { |
||||
const filePanelRef = useRef(null) |
||||
function onThemeChanged (themeType: any) { |
||||
const invert = themeType === 'dark' ? 1 : 0 |
||||
// @ts-ignore
|
||||
const active = filePanelRef.current && filePanelRef.current.querySelector('.active') |
||||
if (active) { |
||||
// @ts-ignore
|
||||
const image = filePanelRef.current.querySelector('.remixui_image') |
||||
image.style.setProperty('filter', `invert(${invert})`) |
||||
} |
||||
} |
||||
|
||||
useEffect(() => { |
||||
const themeModule = verticalIconsPlugin.registry.get('themeModule').api |
||||
themeModule.events.on('themeChanged', (theme: any) => { |
||||
onThemeChanged(theme.quality) |
||||
}) |
||||
}, []) |
||||
|
||||
return ( |
||||
<Fragment> |
||||
{verticalIconsPlugin.targetProfileForChange && |
||||
Object.keys(verticalIconsPlugin.targetProfileForChange).length |
||||
? Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(p => p === 'filePanel') |
||||
.map(p => ( |
||||
<div id="fileExplorerIcons" key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
} data-id="verticalIconsFileExplorerIcons" |
||||
ref={filePanelRef} |
||||
> |
||||
<Icon |
||||
profile={verticalIconsPlugin.targetProfileForChange[p]} |
||||
verticalIconPlugin={verticalIconsPlugin} |
||||
contextMenuAction={itemContextAction} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
/> |
||||
</div> |
||||
)) |
||||
: null} |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export default FilePanel |
@ -0,0 +1,26 @@ |
||||
/* eslint-disable no-use-before-define */ |
||||
/* eslint-disable @typescript-eslint/no-unused-vars */ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
import React, { ReactNode } from 'react' |
||||
import BasicLogo from './BasicLogo' |
||||
interface HomeProps { |
||||
verticalIconPlugin: VerticalIcons |
||||
} |
||||
|
||||
function Home ({ verticalIconPlugin }: HomeProps) { |
||||
return ( |
||||
<div |
||||
className="pl-1 mt-2 remixui_homeIcon" |
||||
onClick={async () => verticalIconPlugin.activateHome()} |
||||
// @ts-ignore
|
||||
plugin="home" |
||||
title="Home" |
||||
data-id="verticalIconsHomeIcon" |
||||
id="verticalIconsHomeIcon" |
||||
> |
||||
<BasicLogo /> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default Home |
@ -0,0 +1,134 @@ |
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */ |
||||
/* eslint-disable no-use-before-define */ |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import VerticalIconsContextMenu from '../vertical-icons-context-menu' |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import React, { Fragment, SyntheticEvent, useEffect, useReducer, useRef, useState } from 'react' |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
import Badge from './Badge' |
||||
|
||||
interface IconProps { |
||||
verticalIconPlugin: VerticalIcons |
||||
profile: IconProfile |
||||
contextMenuAction: (evt: any, profileName: string, documentation: string) => void |
||||
addActive: (profileName: string) => void |
||||
removeActive: () => void |
||||
badgeStatus?: BadgeStatus |
||||
} |
||||
|
||||
export interface IconStatus { |
||||
key: string |
||||
title: string |
||||
type: string |
||||
} |
||||
|
||||
export interface BadgeStatus extends IconStatus { |
||||
text: string |
||||
} |
||||
|
||||
export interface IconProfile { |
||||
description: string |
||||
displayName: string |
||||
documentation: string |
||||
events: any[] |
||||
icon: string |
||||
kind: string |
||||
location: string |
||||
methods: string[] |
||||
name: string |
||||
version: string |
||||
tooltip?: string |
||||
} |
||||
|
||||
function Icon ({ |
||||
profile, |
||||
verticalIconPlugin, |
||||
contextMenuAction, |
||||
addActive, |
||||
removeActive, |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
badgeStatus |
||||
}: IconProps) { |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { tooltip, displayName, name, kind, icon, documentation } = profile |
||||
const [title] = useState(() => { |
||||
const temp = tooltip || displayName || name |
||||
return temp.replace(/^\w/, (word: string) => word.toUpperCase()) |
||||
}) |
||||
const [links, setLinks] = useState<{ Documentation: string, CanDeactivate: boolean }>( |
||||
{} as { Documentation: string, CanDeactivate: boolean } |
||||
) |
||||
// @ts-ignore
|
||||
const [pageX, setPageX] = useState<number>(null) |
||||
// @ts-ignore
|
||||
const [pageY, setPageY] = useState<number>(null) |
||||
const [showContext, setShowContext] = useState(false) |
||||
const [canDeactivate] = useState(false) |
||||
const iconRef = useRef<any>(null) |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
const handleContextMenu = (e: SyntheticEvent & PointerEvent) => { |
||||
const deactivationState = verticalIconPlugin.appManager |
||||
.canDeactivatePlugin(verticalIconPlugin.defaultProfile, { name }) |
||||
if (documentation && documentation.length > 0 && deactivationState) { |
||||
setLinks({ Documentation: documentation, CanDeactivate: deactivationState }) |
||||
} else { |
||||
setLinks({ Documentation: documentation, CanDeactivate: deactivationState }) |
||||
} |
||||
setShowContext(false) |
||||
setPageX(e.pageX) |
||||
setPageY(e.pageY) |
||||
setShowContext(true) |
||||
} |
||||
function closeContextMenu () { |
||||
setShowContext(false) |
||||
} |
||||
|
||||
return ( |
||||
<Fragment> |
||||
<div |
||||
className={name === 'pluginManager' ? 'remixui_icon ml-2 mt-2 mr-2 mb-0 pl-1' : 'remixui_icon m-2 pl-1'} |
||||
onLoad={() => { |
||||
if (name === 'filePanel') { |
||||
addActive(name) |
||||
} |
||||
}} |
||||
onClick={() => { |
||||
removeActive() |
||||
addActive(name) |
||||
verticalIconPlugin.toggle(name) |
||||
}} |
||||
// @ts-ignore
|
||||
plugin={name} |
||||
title={title} |
||||
onContextMenu={(e: any) => { |
||||
e.preventDefault() |
||||
e.stopPropagation() |
||||
handleContextMenu(e) |
||||
}} |
||||
data-id={`verticalIconsKind${name}`} |
||||
id={`verticalIconsKind${name}`} |
||||
ref={iconRef} |
||||
> |
||||
<img className="remixui_image" src={icon} alt={name} /> |
||||
<Badge |
||||
badgeStatus={badgeStatus!} |
||||
/> |
||||
</div> |
||||
{showContext ? ( |
||||
<VerticalIconsContextMenu |
||||
pageX={pageX} |
||||
pageY={pageY} |
||||
links={links} |
||||
profileName={name} |
||||
hideContextMenu={closeContextMenu} |
||||
canBeDeactivated={canDeactivate} |
||||
verticalIconPlugin={verticalIconPlugin} |
||||
contextMenuAction={contextMenuAction} |
||||
/> |
||||
) : null} |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export default Icon |
@ -0,0 +1,66 @@ |
||||
/* eslint-disable no-use-before-define */ |
||||
/* eslint-disable @typescript-eslint/no-unused-vars */ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
import React, { useEffect, useReducer } from 'react' |
||||
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer' |
||||
import Icon, { IconStatus } from './Icon' |
||||
|
||||
function customFilter (p: string) { |
||||
if (p !== 'settings' && p !== 'pluginManager' && |
||||
p !== 'filePanel' && p !== 'debugger' && |
||||
p !== 'compiler' && p !== 'solidity' && |
||||
p !== 'udapp' && p !== 'testing' && p !== 'solidityStaticAnalysis') return true |
||||
return false |
||||
} |
||||
interface OtherIconsProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
} |
||||
|
||||
const initialState = { |
||||
text: '', |
||||
key: '', |
||||
title: '', |
||||
type: '' |
||||
} |
||||
|
||||
function OtherIcons ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: OtherIconsProps) { |
||||
const [badgeStatus, dispatchStatusUpdate] = useReducer(iconBadgeReducer, initialState) |
||||
|
||||
useEffect(() => { |
||||
Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(customFilter) |
||||
.forEach(p => |
||||
verticalIconsPlugin.on(verticalIconsPlugin.targetProfileForChange[p].name, 'statusChanged', (iconStatus: IconStatus) => { |
||||
const action: IconBadgeReducerAction = { |
||||
type: verticalIconsPlugin.targetProfileForChange[p].name, |
||||
payload: { status: iconStatus, verticalIconPlugin: verticalIconsPlugin } |
||||
} |
||||
dispatchStatusUpdate(action) |
||||
})) |
||||
}, []) |
||||
return ( |
||||
<div id="otherIcons"> |
||||
{ |
||||
Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(customFilter) |
||||
.map(p => ( |
||||
<Icon |
||||
profile={verticalIconsPlugin.targetProfileForChange[p]} |
||||
verticalIconPlugin={verticalIconsPlugin} |
||||
contextMenuAction={itemContextAction} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
} |
||||
badgeStatus={badgeStatus} |
||||
/> |
||||
))} |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default OtherIcons |
@ -0,0 +1,36 @@ |
||||
/* eslint-disable no-use-before-define */ |
||||
/* eslint-disable @typescript-eslint/no-unused-vars */ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
import React, { Fragment } from 'react' |
||||
import Icon from './Icon' |
||||
|
||||
interface PluginManagerProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
} |
||||
|
||||
function PluginManager ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: PluginManagerProps) { |
||||
return ( |
||||
<Fragment> |
||||
{Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(p => p === 'pluginManager') |
||||
.map(p => ( |
||||
<Icon |
||||
profile={verticalIconsPlugin.targetProfileForChange[p]} |
||||
verticalIconPlugin={verticalIconsPlugin} |
||||
contextMenuAction={itemContextAction} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
key={ |
||||
verticalIconsPlugin.targetProfileForChange[p] |
||||
.displayName |
||||
} |
||||
/> |
||||
))} |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export default PluginManager |
@ -0,0 +1,67 @@ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import React, { Fragment, MutableRefObject } from 'react' |
||||
import { Chevron } from './Chevron' |
||||
import Debugger from './Debugger' |
||||
import FilePanel from './FilePanel' |
||||
import PluginManager from './PluginManager' |
||||
import Solidity from './Solidity' |
||||
import SolidityStaticAnalysis from './SolidityStaticAnalysis' |
||||
import Udapp from './Udapp' |
||||
|
||||
interface RequiredSectionProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
scrollableRef: MutableRefObject<any> |
||||
} |
||||
|
||||
function RequiredSection ({ verticalIconsPlugin, itemContextAction, addActive, removeActive, scrollableRef }: RequiredSectionProps) { |
||||
return ( |
||||
<Fragment> |
||||
<FilePanel |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
/> |
||||
<PluginManager |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
/> |
||||
<Solidity |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
/> |
||||
<Udapp |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
/> |
||||
<SolidityStaticAnalysis |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
/> |
||||
<Debugger |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
/> |
||||
<Chevron |
||||
divElementRef={scrollableRef} |
||||
cssRule={'fa fa-chevron-up remixui_icon-chevron mt-0 mb-0 ml-1 pl-3'} |
||||
/> |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export { RequiredSection } |
@ -0,0 +1,60 @@ |
||||
/* eslint-disable no-use-before-define */ |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
import React, { useEffect, useRef } from 'react' |
||||
import { Chevron } from './Chevron' |
||||
import Icon from './Icon' |
||||
|
||||
interface SettingsProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
scrollableRef: React.MutableRefObject<any> |
||||
} |
||||
|
||||
function Settings ({ scrollableRef, verticalIconsPlugin, itemContextAction, addActive, removeActive }: SettingsProps) { |
||||
const settingsRef = useRef(null) |
||||
function onThemeChanged (themeType: any) { |
||||
const invert = themeType === 'dark' ? 1 : 0 |
||||
// @ts-ignore
|
||||
const active = settingsRef.current.querySelector('.active') |
||||
if (active) { |
||||
// @ts-ignore
|
||||
const image = settingsRef.current.querySelector('.remixui_image') |
||||
image.style.setProperty('filter', `invert(${invert})`) |
||||
} |
||||
} |
||||
|
||||
useEffect(() => { |
||||
const themeModule = verticalIconsPlugin.registry.get('themeModule').api |
||||
themeModule.events.on('themeChanged', (theme: any) => { |
||||
onThemeChanged(theme.quality) |
||||
}) |
||||
}, []) |
||||
return ( |
||||
<div id="settingsIcons" className="remixui_settings mb-0 flex-grow-0" data-id="vertialIconsSettingsIcons" ref={settingsRef}> |
||||
<Chevron |
||||
divElementRef={scrollableRef} |
||||
cssRule={'fa fa-chevron-down remixui_icon-chevron mt-0 mb-0 ml-1 pl-3'} |
||||
/> |
||||
{Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(p => p === 'settings') |
||||
.map(p => ( |
||||
<Icon |
||||
profile={verticalIconsPlugin.targetProfileForChange[p]} |
||||
verticalIconPlugin={verticalIconsPlugin} |
||||
contextMenuAction={itemContextAction} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
key={ |
||||
verticalIconsPlugin.targetProfileForChange[p] |
||||
.displayName |
||||
} |
||||
/> |
||||
))} |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default Settings |
@ -0,0 +1,58 @@ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import React, { Fragment, useEffect, useReducer } from 'react' |
||||
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer' |
||||
// import Badge from './Badge'
|
||||
import Icon, { IconStatus } from './Icon' |
||||
|
||||
interface SolidityProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
} |
||||
const initialState = { |
||||
text: '', |
||||
key: '', |
||||
title: '', |
||||
type: '' |
||||
} |
||||
|
||||
function Solidity ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: SolidityProps) { |
||||
const [badgeStatus, dispatchStatusUpdate] = useReducer(iconBadgeReducer, initialState) |
||||
|
||||
useEffect(() => { |
||||
verticalIconsPlugin.on('solidity', 'statusChanged', (iconStatus: IconStatus) => { |
||||
const action: IconBadgeReducerAction = { type: 'solidity', payload: { status: iconStatus, verticalIconPlugin: verticalIconsPlugin } } |
||||
dispatchStatusUpdate(action) |
||||
}) |
||||
}, []) |
||||
return ( |
||||
<Fragment> |
||||
{verticalIconsPlugin.targetProfileForChange && |
||||
Object.keys(verticalIconsPlugin.targetProfileForChange).length |
||||
? Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(p => p === 'solidity') |
||||
.map(p => ( |
||||
<div id="compileIcons" key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
}> |
||||
<Icon |
||||
profile={verticalIconsPlugin.targetProfileForChange[p]} |
||||
verticalIconPlugin={verticalIconsPlugin} |
||||
contextMenuAction={itemContextAction} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
} |
||||
badgeStatus={badgeStatus} |
||||
/> |
||||
</div> |
||||
)) |
||||
: null} |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export default Solidity |
@ -0,0 +1,58 @@ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import React, { Fragment, useEffect, useReducer } from 'react' |
||||
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer' |
||||
// import Badge from './Badge'
|
||||
import Icon, { IconStatus } from './Icon' |
||||
|
||||
interface SolidityStaticAnalysisProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
} |
||||
|
||||
const initialState = { |
||||
text: '', |
||||
key: '', |
||||
title: '', |
||||
type: '' |
||||
} |
||||
|
||||
function SolidityStaticAnalysis ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: SolidityStaticAnalysisProps) { |
||||
const [badgeStatus, dispatchStatusUpdate] = useReducer(iconBadgeReducer, initialState) |
||||
useEffect(() => { |
||||
verticalIconsPlugin.on('solidityStaticAnalysis', 'statusChanged', (iconStatus: IconStatus) => { |
||||
const action: IconBadgeReducerAction = { type: 'solidityStaticAnalysis', payload: { status: iconStatus, verticalIconPlugin: verticalIconsPlugin } } |
||||
dispatchStatusUpdate(action) |
||||
}) |
||||
}, []) |
||||
return ( |
||||
<Fragment> |
||||
{verticalIconsPlugin.targetProfileForChange && |
||||
Object.keys(verticalIconsPlugin.targetProfileForChange).length |
||||
? Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(p => p === 'solidityStaticAnalysis') |
||||
.map(p => ( |
||||
<div id="analysisIcons" className="remixui_iconContainer" key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
}> |
||||
<Icon |
||||
profile={verticalIconsPlugin.targetProfileForChange[p]} |
||||
verticalIconPlugin={verticalIconsPlugin} |
||||
contextMenuAction={itemContextAction} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
} |
||||
badgeStatus={badgeStatus} |
||||
/> |
||||
</div> |
||||
)) |
||||
: null} |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export default SolidityStaticAnalysis |
@ -0,0 +1,60 @@ |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
// eslint-disable-next-line no-use-before-define
|
||||
import React, { Fragment, useEffect, useReducer } from 'react' |
||||
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer' |
||||
import Icon, { IconStatus } from './Icon' |
||||
|
||||
interface UdappProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
itemContextAction: (e: any, name: string, documentation: string) => Promise<void> |
||||
addActive: (name: string) => void |
||||
removeActive: () => void |
||||
} |
||||
|
||||
const initialState = { |
||||
text: '', |
||||
key: '', |
||||
title: '', |
||||
type: '' |
||||
} |
||||
|
||||
function Udapp ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: UdappProps) { |
||||
const [badgeStatus, dispatchStatusUpdate] = useReducer(iconBadgeReducer, initialState) |
||||
|
||||
useEffect(() => { |
||||
verticalIconsPlugin.on('udapp', 'statusChanged', (iconStatus: IconStatus) => { |
||||
const action: IconBadgeReducerAction = { type: 'udapp', payload: { status: iconStatus, verticalIconPlugin: verticalIconsPlugin } } |
||||
dispatchStatusUpdate(action) |
||||
}) |
||||
}, []) |
||||
|
||||
return ( |
||||
<Fragment> |
||||
{verticalIconsPlugin.targetProfileForChange && |
||||
Object.keys(verticalIconsPlugin.targetProfileForChange).length |
||||
? Object.keys(verticalIconsPlugin.targetProfileForChange) |
||||
.filter(p => p === 'udapp') |
||||
.map(p => ( |
||||
<div id="runIcons" data-id="verticalIconsKindUdapp" key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
} |
||||
> |
||||
<Icon |
||||
profile={verticalIconsPlugin.targetProfileForChange[p]} |
||||
verticalIconPlugin={verticalIconsPlugin} |
||||
contextMenuAction={itemContextAction} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
key={ |
||||
verticalIconsPlugin.targetProfileForChange[p].displayName |
||||
} |
||||
badgeStatus={badgeStatus} |
||||
/> |
||||
</div> |
||||
)) |
||||
: null} |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export default Udapp |
@ -0,0 +1,44 @@ |
||||
/* eslint-disable @typescript-eslint/no-unused-vars */ |
||||
import helper from 'apps/remix-ide/src/lib/helper' |
||||
import { BadgeStatus, IconStatus } from '../components/Icon' |
||||
import React, { MutableRefObject } from 'react' |
||||
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' |
||||
|
||||
export type IconBadgeReducerAction = { |
||||
readonly type: string |
||||
readonly payload: any |
||||
} |
||||
|
||||
/** |
||||
* Set a new status for the @arg name |
||||
* @param {String} name |
||||
* @param {Object} status |
||||
*/ |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function setIconStatus (name: string, status: IconStatus) { |
||||
if (status.key === 'none') return { ...status, text: '' } // remove status
|
||||
|
||||
let text = '' |
||||
let key = '' |
||||
if (typeof status.key === 'number') { |
||||
key = status.key |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
text = key |
||||
} else key = helper.checkSpecialChars(status.key) ? '' : status.key |
||||
|
||||
let thisType = '' |
||||
if (status.type === 'error') { |
||||
thisType = 'danger' // to use with bootstrap
|
||||
} else thisType = helper.checkSpecialChars(status.type) ? '' : status.type! |
||||
const title = helper.checkSpecialChars(status.title) ? '' : status.title |
||||
return { title, type: thisType, key, text } |
||||
} |
||||
|
||||
export function iconBadgeReducer (state: BadgeStatus, action: IconBadgeReducerAction) { |
||||
const { status, ref, verticalIconPlugin } = action.payload |
||||
if (Object.keys(verticalIconPlugin.targetProfileForChange).includes(action.type)) { |
||||
const setStatus = setIconStatus(action.type, status) |
||||
return setStatus |
||||
} |
||||
return state |
||||
} |
@ -0,0 +1,124 @@ |
||||
.remixui_homeIcon { |
||||
/* display: block; */ |
||||
width: 42px; |
||||
height: 42px; |
||||
cursor: pointer; |
||||
} |
||||
.remixui_homeIcon svg path { |
||||
fill: var(--primary); |
||||
} |
||||
.remixui_homeIcon svg polygon { |
||||
fill: var(--primary); |
||||
} |
||||
.remixui_icons { |
||||
display: flex; |
||||
flex-flow: column nowrap; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
} |
||||
.remixui_icon { |
||||
cursor: pointer; |
||||
margin-bottom: 3px; |
||||
position: 12px; |
||||
width: 36px; |
||||
height: 36px; |
||||
padding: relative; |
||||
border-radius: 8px; |
||||
} |
||||
.remixui_icon img { |
||||
width: 28px; |
||||
height: 28px; |
||||
padding: 4px; |
||||
filter: invert(0.5); |
||||
} |
||||
.remixui_image { |
||||
} |
||||
.remixui_icon svg { |
||||
width: 28px; |
||||
height: 28px; |
||||
padding: 4px; |
||||
} |
||||
.remixui_icon[title='Settings'] { |
||||
order: 5; |
||||
align-self: center; |
||||
bottom: 0; |
||||
} |
||||
.remixui_status { |
||||
position: relative; |
||||
bottom: 0; |
||||
right: 0; |
||||
left: 12px; |
||||
top: -13px; |
||||
} |
||||
.remixui_statusCheck { |
||||
font-size: 1.2em; |
||||
} |
||||
.remixui_statusWithBG { |
||||
border-radius: 8px; |
||||
background-color: var(--danger); |
||||
color: var(--light); |
||||
font-size: 12px; |
||||
height: 15px; |
||||
text-align: center; |
||||
font-weight: bold; |
||||
padding-left: 5px; |
||||
padding-right: 5px; |
||||
} |
||||
|
||||
.remixui_verticalIconContextcontainer { |
||||
display: block; |
||||
position: fixed; |
||||
border-radius: 2px; |
||||
z-index: 1000; |
||||
box-shadow: 0 0 4px var(--dark); |
||||
} |
||||
.remixui_verticalIconContextcontainer:focus { |
||||
outline: 0; |
||||
} |
||||
.remixui_liitem { |
||||
padding: 2px; |
||||
padding-left: 6px; |
||||
cursor: pointer; |
||||
color: var(--text-dark); |
||||
background-color: var(--light); |
||||
} |
||||
.remixui_liitem:hover { |
||||
background-color: var(--secondary); |
||||
} |
||||
|
||||
.remixui_scrollbar { |
||||
overflow-y: scroll; |
||||
scrollbar-width: none; /* Firefox hide scrollbar */ |
||||
-ms-overflow-style: none; |
||||
} |
||||
.remixui_scrollable-container { |
||||
flex-basis: 510px; |
||||
flex-grow: 2; |
||||
/* border-bottom: 3px solid #3f4455; */ |
||||
} |
||||
.remixui_scrollbar::-webkit-scrollbar { /* Chrome, Safari and other Webkit browsers*/ |
||||
display: none; |
||||
} |
||||
.remixui_hide-scroll { |
||||
overflow-x: 'hidden'; |
||||
} |
||||
.remixui_default-icons-container { |
||||
border-bottom: 2px solid #3f4455; |
||||
} |
||||
.remixui_icon-chevron { |
||||
z-index: 1000; |
||||
} |
||||
|
||||
.remixui_settings { |
||||
flex-basis: 50px; |
||||
} |
||||
|
||||
.remixui_requiredSection { |
||||
flex-basis: 180px; |
||||
flex-grow: 1; |
||||
} |
||||
|
||||
#menuitems { |
||||
list-style: none; |
||||
margin: 0px; |
||||
} |
@ -0,0 +1,139 @@ |
||||
/* eslint-disable no-use-before-define */ |
||||
/* eslint-disable @typescript-eslint/no-unused-vars */ |
||||
import React, { |
||||
Fragment, |
||||
useEffect, |
||||
useRef |
||||
} from 'react' |
||||
|
||||
import './remix-ui-vertical-icons-panel.css' |
||||
import OtherIcons from './components/OtherIcons' |
||||
import { VerticalIcons } from '../../types/vertical-icons-panel' |
||||
import Home from './components/Home' |
||||
import Settings from './components/Settings' |
||||
import { RequiredSection } from './components/RequiredSection' |
||||
export interface RemixUiVerticalIconsPanelProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
} |
||||
|
||||
let scrollHeight: any |
||||
|
||||
export function RemixUiVerticalIconsPanel ({ |
||||
verticalIconsPlugin |
||||
}: RemixUiVerticalIconsPanelProps) { |
||||
const scrollableRef = useRef<any>() |
||||
const iconPanelRef = useRef<any>() |
||||
|
||||
function onThemeChanged (themeType: any) { |
||||
const invert = themeType === 'dark' ? 1 : 0 |
||||
// @ts-ignore
|
||||
const active = iconPanelRef.current.querySelector('.active') |
||||
if (active) { |
||||
// @ts-ignore
|
||||
const image = iconPanelRef.current.querySelector('.remixui_image') |
||||
image.style.setProperty('filter', `invert(${invert})`) |
||||
} |
||||
} |
||||
|
||||
function removeActive () { |
||||
// @ts-ignore
|
||||
const images = iconPanelRef.current.querySelectorAll('.remixui_image') |
||||
images.forEach(function (im: any) { |
||||
im.style.setProperty('filter', 'invert(0.5)') |
||||
}) |
||||
|
||||
// remove active
|
||||
// @ts-ignore
|
||||
const currentActive = iconPanelRef.current.querySelector('.active') |
||||
if (currentActive) { |
||||
currentActive.classList.remove('active') |
||||
} |
||||
} |
||||
|
||||
function addActive (name: string) { |
||||
if (name === 'home') return |
||||
const themeType = verticalIconsPlugin.registry.get('themeModule').api.currentTheme().quality |
||||
const invert = themeType === 'dark' ? 1 : 0 |
||||
const brightness = themeType === 'dark' ? '150' : '0' // should be >100 for icons with color
|
||||
// @ts-ignore
|
||||
const nextActive = iconPanelRef.current.querySelector(`[plugin="${name}"]`) |
||||
if (nextActive) { |
||||
const image = nextActive.querySelector('.remixui_image') |
||||
nextActive.classList.add('active') |
||||
image.style.setProperty('filter', `invert(${invert}) grayscale(1) brightness(${brightness}%)`) |
||||
} |
||||
} |
||||
|
||||
async function itemContextAction (e: any, name: string, documentation: string) { |
||||
verticalIconsPlugin.appManager.deactivatePlugin(name) |
||||
if (e.target.parentElement.classList.contains('active')) { |
||||
verticalIconsPlugin.select('filePanel') |
||||
} |
||||
verticalIconsPlugin.renderComponent() |
||||
} |
||||
|
||||
useEffect(() => { |
||||
const themeModule = verticalIconsPlugin.registry.get('themeModule').api |
||||
themeModule.events.on('themeChanged', (theme: any) => { |
||||
onThemeChanged(theme.quality) |
||||
}) |
||||
}, []) |
||||
|
||||
useEffect(() => { |
||||
const themeModule = verticalIconsPlugin.registry.get('themeModule').api |
||||
themeModule.events.on('themeChanged', (theme: any) => { |
||||
onThemeChanged(theme.quality) |
||||
}) |
||||
}, []) |
||||
|
||||
useEffect(() => { |
||||
if (verticalIconsPlugin.targetProfileForChange && verticalIconsPlugin.targetProfileForChange.udapp) { |
||||
const doWalkThroughEvent = new Event('doWalkThrough') |
||||
document.dispatchEvent(doWalkThroughEvent) |
||||
} |
||||
}, [Object.keys(verticalIconsPlugin.targetProfileForChange).length]) |
||||
|
||||
return ( |
||||
<div id="iconsP" className="h-100"> |
||||
<div className="remixui_icons d-flex flex-column vh-100" ref={iconPanelRef}> |
||||
<Home verticalIconPlugin={verticalIconsPlugin} /> |
||||
<div className={scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight |
||||
? 'remixui_default-icons-container remixui_requiredSection' : 'remixui_requiredSection'}> |
||||
<RequiredSection |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
scrollableRef={scrollableRef} |
||||
/> |
||||
</div> |
||||
<div |
||||
id="remixuiScrollable" |
||||
className={scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight |
||||
? 'remixui_default-icons-container remixui_scrollable-container remixui_scrollbar remixui_hide-scroll' |
||||
: 'remixui_scrollable-container remixui_scrollbar remixui_hide-scroll'} |
||||
ref={scrollableRef} |
||||
> |
||||
<OtherIcons |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
/> |
||||
</div> |
||||
{verticalIconsPlugin.targetProfileForChange && |
||||
Object.keys(verticalIconsPlugin.targetProfileForChange).length ? ( |
||||
<Fragment> |
||||
<Settings |
||||
verticalIconsPlugin={verticalIconsPlugin} |
||||
addActive={addActive} |
||||
removeActive={removeActive} |
||||
itemContextAction={itemContextAction} |
||||
scrollableRef={scrollableRef} |
||||
/> |
||||
</Fragment> |
||||
) : null} |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
@ -0,0 +1,121 @@ |
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */ |
||||
/* eslint-disable @typescript-eslint/no-unused-vars */ |
||||
/* eslint-disable no-use-before-define */ |
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import React, { Fragment, useEffect, useRef } from 'react' |
||||
import { VerticalIcons } from '../../types/vertical-icons-panel' |
||||
|
||||
export interface VerticalIconsContextMenuProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> { |
||||
pageX: number |
||||
pageY: number |
||||
profileName: string |
||||
links: { Documentation: string, CanDeactivate: boolean } |
||||
canBeDeactivated: boolean |
||||
verticalIconPlugin: VerticalIcons |
||||
hideContextMenu: () => void |
||||
contextMenuAction: (evt: any, profileName: string, documentation: string) => void |
||||
} |
||||
|
||||
interface MenuLinksProps { |
||||
listItems: { Documentation: string, CanDeactivate: boolean } |
||||
hide: () => void |
||||
profileName: string |
||||
canBeDeactivated: boolean |
||||
verticalIconPlugin: VerticalIcons |
||||
ref?: React.MutableRefObject<any> |
||||
toggle: (name: string) => void |
||||
contextMenuAction: (evt: any, profileName: string, documentation: string) => void |
||||
} |
||||
|
||||
interface MenuProps { |
||||
verticalIconsPlugin: VerticalIcons |
||||
profileName: string |
||||
listItems: { Documentation: string, CanDeactivate: boolean } |
||||
hide: () => void |
||||
} |
||||
|
||||
const requiredModules = [ |
||||
'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', |
||||
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', |
||||
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic'] |
||||
const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider'] |
||||
|
||||
function VerticalIconsContextMenu (props: VerticalIconsContextMenuProps) { |
||||
const menuRef = useRef(null) |
||||
useEffect(() => { |
||||
document.addEventListener('click', props.hideContextMenu) |
||||
return () => document.removeEventListener('click', props.hideContextMenu) |
||||
}, []) |
||||
useEffect(() => { |
||||
// @ts-ignore
|
||||
menuRef.current.focus() |
||||
}, []) |
||||
return ( |
||||
<div |
||||
id="menuItemsContainer" |
||||
className="p-1 remixui_verticalIconContextcontainer bg-light shadow border" |
||||
onBlur={props.hideContextMenu} |
||||
style={{ |
||||
left: props.pageX, |
||||
top: props.pageY, |
||||
display: 'block' |
||||
|
||||
}} |
||||
ref={menuRef} |
||||
tabIndex={1} |
||||
> |
||||
<ul id="menuitems"> |
||||
<MenuForLinks |
||||
hide={props.hideContextMenu} |
||||
listItems={props.links} |
||||
profileName={props.profileName} |
||||
canBeDeactivated={props.canBeDeactivated} |
||||
verticalIconPlugin={props.verticalIconPlugin} |
||||
toggle={props.verticalIconPlugin.toggle} |
||||
contextMenuAction={props.contextMenuAction} |
||||
/> |
||||
</ul> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function MenuForLinks ({ |
||||
listItems, |
||||
hide, |
||||
profileName, |
||||
contextMenuAction |
||||
}: MenuLinksProps) { |
||||
return ( |
||||
<Fragment> |
||||
{listItems.CanDeactivate && !requiredModules.includes(profileName) |
||||
? <li |
||||
id="menuitemdeactivate" |
||||
onClick={(evt) => { |
||||
contextMenuAction(evt, profileName, listItems.Documentation) |
||||
hide() |
||||
}} |
||||
className="remixui_liitem" |
||||
> |
||||
Deactivate |
||||
</li> |
||||
: null |
||||
} |
||||
{(listItems.Documentation && listItems.Documentation.length > 0) && |
||||
<li |
||||
id="menuitemdocumentation" |
||||
className="remixui_liitem" |
||||
> |
||||
<a |
||||
onClick={hide} |
||||
href={listItems.Documentation} |
||||
target="_blank" |
||||
> |
||||
Documentation |
||||
</a> |
||||
</li>} |
||||
</Fragment> |
||||
) |
||||
} |
||||
|
||||
export default VerticalIconsContextMenu |
@ -0,0 +1,21 @@ |
||||
{ |
||||
"extends": "../../../tsconfig.base.json", |
||||
"compilerOptions": { |
||||
"jsx": "react-jsx", |
||||
"allowJs": true, |
||||
"esModuleInterop": true, |
||||
"allowSyntheticDefaultImports": true, |
||||
"forceConsistentCasingInFileNames": true, |
||||
"strict": true, |
||||
"noImplicitReturns": true, |
||||
"noFallthroughCasesInSwitch": true, |
||||
"resolveJsonModule": true |
||||
}, |
||||
"files": [], |
||||
"include": [], |
||||
"references": [ |
||||
{ |
||||
"path": "./tsconfig.lib.json" |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,14 @@ |
||||
{ |
||||
"extends": "./tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "../../../dist/out-tsc", |
||||
"types": ["node"], |
||||
"resolveJsonModule": true |
||||
}, |
||||
"files": [ |
||||
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", |
||||
"../../../node_modules/@nrwl/react/typings/image.d.ts" |
||||
], |
||||
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"], |
||||
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] |
||||
} |
@ -0,0 +1,110 @@ |
||||
/* eslint-disable @typescript-eslint/ban-types */ |
||||
/* eslint-disable no-use-before-define */ |
||||
import { Plugin } from '@remixproject/engine/lib/abstract' |
||||
import * as packageJson from '../../../../package.json' |
||||
import * as registry from 'apps/remix-ide/src/global/registry' |
||||
import { RemixAppManager } from '@remix-ui/plugin-manager' |
||||
|
||||
export type Kind = |
||||
| 'fileexplorer' |
||||
| 'compiler' |
||||
| 'udapp' |
||||
| 'testing' |
||||
| 'analysis' |
||||
| 'debugging' |
||||
| 'settings' |
||||
| 'none' |
||||
|
||||
type IconKindType = { |
||||
kind: {} |
||||
} |
||||
|
||||
interface defaultModuleProfile { |
||||
name: string |
||||
displayName: string |
||||
description: string |
||||
version: packageJson.version |
||||
methods: string[] |
||||
} |
||||
|
||||
interface PassedProfile { |
||||
name: string |
||||
displayName: string |
||||
description: string |
||||
version: packageJson.version |
||||
methods: string[] |
||||
icon?: string |
||||
tooltip?: string |
||||
kind?: string |
||||
documentation?: string |
||||
} |
||||
|
||||
interface targetProfileIcons { |
||||
profile: PassedProfile |
||||
} |
||||
export class VerticalIcons extends Plugin<any, any> { |
||||
events: EventEmitter |
||||
appManager: RemixAppManager |
||||
htmlElement: HTMLDivElement |
||||
icons: any |
||||
iconKind: {} |
||||
iconStatus: {} |
||||
defaultProfile: defaultModuleProfile |
||||
targetProfileForChange: any |
||||
targetProfileForRemoval: any |
||||
registry: registry |
||||
keys: string[] |
||||
types: string[] |
||||
renderComponent(): void |
||||
linkContent(profile: any): void |
||||
unlinkContent(profile: any): void |
||||
listenOnStatus(profile: any): void |
||||
activateHome(): void |
||||
/** |
||||
* Add an icon to the map |
||||
* @param {ModuleProfile} profile The profile of the module |
||||
*/ |
||||
addIcon({ kind, name, icon, displayName, tooltip, documentation }: any): void |
||||
/** |
||||
* resolve a classes list for @arg key |
||||
* @param {Object} key |
||||
* @param {Object} type |
||||
*/ |
||||
resolveClasses(key: any, type: any): any |
||||
/** |
||||
* Set a new status for the @arg name |
||||
* @param {String} name |
||||
* @param {Object} status |
||||
*/ |
||||
setIconStatus(name: string, status: any): void |
||||
/** |
||||
* Remove an icon from the map |
||||
* @param {ModuleProfile} profile The profile of the module |
||||
*/ |
||||
removeIcon({ name }: any): void |
||||
/** |
||||
* Remove active for the current activated icons |
||||
*/ |
||||
removeActive(): void |
||||
/** |
||||
* Add active for the new activated icon |
||||
* @param {string} name Name of profile of the module to activate |
||||
*/ |
||||
addActive(name: string): void |
||||
/** |
||||
* Set an icon as active |
||||
* @param {string} name Name of profile of the module to activate |
||||
*/ |
||||
select(name: string): void |
||||
/** |
||||
* Toggles the side panel for plugin |
||||
* @param {string} name Name of profile of the module to activate |
||||
*/ |
||||
toggle(name: string): void |
||||
updateActivations(name: any): void |
||||
onThemeChanged(themeType: any): void |
||||
itemContextMenu(e: any, name: any, documentation: any): Promise<void> |
||||
render(): any |
||||
view: any |
||||
} |
||||
import EventEmitter = require('events') |
Loading…
Reference in new issue