Merge branch 'master' into injected-web3

pull/1975/head
David Disu 3 years ago committed by GitHub
commit 2c3b9b1f4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/debugger/src/app/debugger-api.ts
  2. 2
      apps/remix-ide-e2e/src/tests/generalSettings.test.ts
  3. 4
      apps/remix-ide/src/app.js
  4. 3
      apps/remix-ide/src/app/components/panel.ts
  5. 37
      apps/remix-ide/src/app/components/side-panel.tsx
  6. 110
      apps/remix-ide/src/app/components/vertical-icons.js
  7. 116
      apps/remix-ide/src/app/components/vertical-icons.tsx
  8. 4
      apps/remix-ide/src/remixAppManager.js
  9. 2
      apps/remix-ide/src/walkthroughService.js
  10. 3
      libs/remix-core-plugin/src/lib/compiler-content-imports.ts
  11. 7
      libs/remix-ui/helper/src/lib/helper-components.tsx
  12. 2
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.css
  13. 16
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
  14. 2
      libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
  15. 2
      libs/remix-ui/panel/src/lib/types/index.ts
  16. 20
      libs/remix-ui/vertical-icons-panel/.eslintrc.json
  17. 3
      libs/remix-ui/vertical-icons-panel/src/index.ts
  18. 11
      libs/remix-ui/vertical-icons-panel/src/lib/components/Badge.tsx
  19. 2
      libs/remix-ui/vertical-icons-panel/src/lib/components/BasicLogo.tsx
  20. 13
      libs/remix-ui/vertical-icons-panel/src/lib/components/Chevron.tsx
  21. 41
      libs/remix-ui/vertical-icons-panel/src/lib/components/Debugger.tsx
  22. 59
      libs/remix-ui/vertical-icons-panel/src/lib/components/FilePanel.tsx
  23. 14
      libs/remix-ui/vertical-icons-panel/src/lib/components/Home.tsx
  24. 66
      libs/remix-ui/vertical-icons-panel/src/lib/components/Icon.tsx
  25. 33
      libs/remix-ui/vertical-icons-panel/src/lib/components/IconList.tsx
  26. 43
      libs/remix-ui/vertical-icons-panel/src/lib/components/OtherIcons.tsx
  27. 36
      libs/remix-ui/vertical-icons-panel/src/lib/components/PluginManager.tsx
  28. 72
      libs/remix-ui/vertical-icons-panel/src/lib/components/RequiredSection.tsx
  29. 60
      libs/remix-ui/vertical-icons-panel/src/lib/components/Settings.tsx
  30. 41
      libs/remix-ui/vertical-icons-panel/src/lib/components/Solidity.tsx
  31. 41
      libs/remix-ui/vertical-icons-panel/src/lib/components/SolidityStaticAnalysis.tsx
  32. 42
      libs/remix-ui/vertical-icons-panel/src/lib/components/Udapp.tsx
  33. 29
      libs/remix-ui/vertical-icons-panel/src/lib/reducers/iconBadgeReducer.ts
  34. 3
      libs/remix-ui/vertical-icons-panel/src/lib/reducers/verticalScrollReducer.ts
  35. 25
      libs/remix-ui/vertical-icons-panel/src/lib/remix-ui-vertical-icons-panel.css
  36. 161
      libs/remix-ui/vertical-icons-panel/src/lib/remix-ui-vertical-icons-panel.tsx
  37. 10
      libs/remix-ui/vertical-icons-panel/src/lib/types/index.ts
  38. 46
      libs/remix-ui/vertical-icons-panel/src/lib/vertical-icons-context-menu.tsx
  39. 12
      libs/remix-ui/vertical-icons-panel/tsconfig.json
  40. 3
      libs/remix-ui/vertical-icons-panel/tsconfig.lib.json
  41. 111
      libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel.d.ts
  42. 2
      libs/remix-url-resolver/src/resolve.ts
  43. 2
      libs/remix-url-resolver/tests/test.ts

@ -83,7 +83,7 @@ export const DebuggerApiMixin = (Base) => class extends Base {
const target = (address && remixDebug.traceHelper.isContractCreation(address)) ? receipt.contractAddress : address
const targetAddress = target || receipt.contractAddress || receipt.to
const codeAtAddress = await this._web3.eth.getCode(targetAddress)
const output = await this.call('fetchAndCompile', 'resolve', targetAddress, codeAtAddress, 'browser/.debug')
const output = await this.call('fetchAndCompile', 'resolve', targetAddress, codeAtAddress, '.debug')
if (output) {
return new CompilerAbstract(output.languageversion, output.data, output.source)
}

@ -19,7 +19,7 @@ module.exports = {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000)
.waitForElementVisible('*[data-id="settingsTabGenerateContractMetadataLabel"]', 5000)
.verify.elementPresent('[data-id="settingsTabGenerateContractMetadata"]:checked')
.click('*[data-id="verticalIconsFileExplorerIcons"]')
.click('*[data-id="verticalIconsKindfilePanel"]')
.click('[data-id="treeViewLitreeViewItemcontracts"]')
.openFile('contracts/3_Ballot.sol')
.click('*[data-id="verticalIconsKindsolidity"]')

@ -225,8 +225,8 @@ class AppComponent {
self.engine.register([appPanel, tabProxy])
// those views depend on app_manager
self.menuicons = new VerticalIcons(appManager)
self.sidePanel = new SidePanel(appManager, self.menuicons)
self.menuicons = new VerticalIcons()
self.sidePanel = new SidePanel()
self.hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent(

@ -49,8 +49,7 @@ export class AbstractPanel extends HostPlugin {
* @param {String} name The name of the plugin to display the content
*/
showContent (name) {
if (!this.plugins[name]) throw new Error(`Plugin ${name} is not yet activated`)
if (!this.plugins[name]) throw new Error(`Plugin ${name} is not yet activated`)
Object.values(this.plugins).forEach(plugin => {
plugin.active = false
})

@ -4,8 +4,6 @@ import ReactDOM from 'react-dom'
import { AbstractPanel } from './panel'
import { RemixPluginPanel } from '@remix-ui/panel'
import packageJson from '../../../../../package.json'
import { RemixAppManager } from '../../remixAppManager'
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel'
import RemixUIPanelHeader from 'libs/remix-ui/panel/src/lib/plugins/panel-header'
// const csjs = require('csjs-inject')
@ -17,20 +15,18 @@ const sidePanel = {
methods: ['addView', 'removeView']
}
// TODO merge with vertical-icons.js
export class SidePanel extends AbstractPanel {
appManager: RemixAppManager
sideelement: any
verticalIcons: VerticalIcons;
constructor (appManager: RemixAppManager, verticalIcons: VerticalIcons) {
constructor() {
super(sidePanel)
this.appManager = appManager
this.sideelement = document.createElement('section')
this.sideelement.setAttribute('class', 'panel plugin-manager')
this.verticalIcons = verticalIcons
}
onActivation() {
this.renderComponent()
// Toggle content
verticalIcons.events.on('toggleContent', (name) => {
this.on('menuicons', 'toggleContent', (name) => {
if (!this.plugins[name]) return
if (this.plugins[name].active) {
// TODO: Only keep `this.emit` (issue#2210)
@ -44,7 +40,7 @@ export class SidePanel extends AbstractPanel {
this.events.emit('showing', name)
})
// Force opening
verticalIcons.events.on('showContent', (name) => {
this.on('menuicons', 'showContent', (name) => {
if (!this.plugins[name]) return
this.showContent(name)
// TODO: Only keep `this.emit` (issue#2210)
@ -53,25 +49,22 @@ export class SidePanel extends AbstractPanel {
})
}
onActivation () {
this.renderComponent()
}
focus (name) {
focus(name) {
this.emit('focusChanged', name)
super.focus(name)
}
removeView (profile) {
removeView(profile) {
if (this.plugins[profile.name].active) this.call('menuicons', 'select', 'filePanel')
super.removeView(profile)
this.emit('pluginDisabled', profile.name)
this.call('menuicons', 'unlinkContent', profile)
this.renderComponent()
}
addView (profile, view) {
addView(profile, view) {
super.addView(profile, view)
this.verticalIcons.linkContent(profile)
this.call('menuicons', 'linkContent', profile)
this.renderComponent()
}
@ -79,17 +72,17 @@ export class SidePanel extends AbstractPanel {
* Display content and update the header
* @param {String} name The name of the plugin to display
*/
async showContent (name) {
async showContent(name) {
super.showContent(name)
this.emit('focusChanged', name)
this.renderComponent()
}
render () {
render() {
return this.sideelement
}
renderComponent () {
ReactDOM.render(<RemixPluginPanel header={<RemixUIPanelHeader plugins={this.plugins}></RemixUIPanelHeader>} plugins={this.plugins}/>, this.sideelement)
renderComponent() {
ReactDOM.render(<RemixPluginPanel header={<RemixUIPanelHeader plugins={this.plugins}></RemixUIPanelHeader>} plugins={this.plugins} />, this.sideelement)
}
}

@ -1,110 +0,0 @@
import * as packageJson from '../../../../../package.json'
import ReactDOM from 'react-dom'
import React from 'react' // eslint-disable-line
// eslint-disable-next-line no-unused-vars
import { RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel'
import Registry from '../state/registry'
const { Plugin } = require('@remixproject/engine')
const EventEmitter = require('events')
const profile = {
name: 'menuicons',
displayName: 'Vertical Icons',
description: '',
version: packageJson.version,
methods: ['select', 'unlinkContent']
}
// TODO merge with side-panel.js. VerticalIcons should not be a plugin
export class VerticalIcons extends Plugin {
constructor (appManager) {
super(profile)
this.events = new EventEmitter()
this.appManager = appManager
this.htmlElement = document.createElement('div')
this.htmlElement.setAttribute('id', 'icon-panel')
this.icons = {}
this.iconKind = {}
this.iconStatus = {}
this.defaultProfile = profile
this.targetProfileForChange = {}
this.targetProfileForRemoval = {}
this.registry = Registry.getInstance()
this.keys = ['succeed', 'edited', 'none', 'loading', 'failed']
this.types = ['error', 'warning', 'success', 'info', '']
}
renderComponent () {
ReactDOM.render(
<RemixUiVerticalIconsPanel
verticalIconsPlugin={this}
/>,
this.htmlElement)
}
onActivation () {
this.renderComponent()
}
linkContent (profile) {
if (!profile.icon) return
if (!profile.kind) profile.kind = 'none'
this.targetProfileForChange[profile.name] = profile
this.listenOnStatus(profile)
this.renderComponent()
}
unlinkContent (profile) {
this.targetProfileForRemoval = profile
this.removeIcon(profile)
this.renderComponent()
}
listenOnStatus (profile) {
}
/**
* Remove an icon from the map
* @param {ModuleProfile} profile The profile of the module
*/
removeIcon ({ name }) {
if (this.targetProfileForChange[name]) delete this.targetProfileForChange[name]
setTimeout(() => {
this.renderComponent()
}, 150)
}
/**
* Set an icon as active
* @param {string} name Name of profile of the module to activate
*/
select (name) {
// TODO: Only keep `this.emit` (issue#2210)
this.emit('showContent', name)
this.events.emit('showContent', name)
}
onThemeChanged (themeType) {
const invert = themeType === 'dark' ? 1 : 0
const active = this.view.querySelector('.active')
if (active) {
const image = active.querySelector('.image')
image.style.setProperty('filter', `invert(${invert})`)
}
}
/**
* Toggles the side panel for plugin
* @param {string} name Name of profile of the module to activate
*/
toggle (name) {
// TODO: Only keep `this.emit` (issue#2210)
this.emit('toggleContent', name)
this.events.emit('toggleContent', name)
}
render () {
return this.htmlElement
}
}

@ -0,0 +1,116 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import ReactDOM from 'react-dom'
import Registry from '../state/registry'
import packageJson from '../../../../../package.json'
import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import { IconRecord, RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel'
import { Profile } from '@remixproject/plugin-utils'
import { timeStamp } from 'console'
const profile = {
name: 'menuicons',
displayName: 'Vertical Icons',
description: '',
version: packageJson.version,
methods: ['select', 'unlinkContent', 'linkContent'],
events: ['toggleContent', 'showContent']
}
export class VerticalIcons extends Plugin {
events: EventEmitter
htmlElement: HTMLDivElement
icons: Record<string, IconRecord> = {}
constructor () {
super(profile)
this.events = new EventEmitter()
this.htmlElement = document.createElement('div')
this.htmlElement.setAttribute('id', 'icon-panel')
}
renderComponent () {
const fixedOrder = ['filePanel', 'solidity','udapp', 'debugger', 'solidityStaticAnalysis', 'solidityUnitTesting', 'pluginManager']
const divived = Object.values(this.icons).map((value) => { return {
...value,
isRequired: fixedOrder.indexOf(value.profile.name) > -1
}}).sort((a,b) => {
return a.timestamp - b.timestamp
})
const required = divived.filter((value) => value.isRequired).sort((a,b) => {
return fixedOrder.indexOf(a.profile.name) - fixedOrder.indexOf(b.profile.name)
})
const sorted: IconRecord[] = [
...required,
...divived.filter((value) => { return !value.isRequired })
]
ReactDOM.render(
<RemixUiVerticalIconsPanel
verticalIconsPlugin={this}
icons={sorted}
/>,
this.htmlElement)
}
onActivation () {
this.renderComponent()
this.on('sidePanel', 'focusChanged', (name: string) => {
Object.keys(this.icons).map((o) => {
this.icons[o].active = false
})
this.icons[name].active = true
this.renderComponent()
})
}
async linkContent (profile: Profile) {
if (!profile.icon) return
if (!profile.kind) profile.kind = 'none'
this.icons[profile.name] = {
profile: profile,
active: false,
canbeDeactivated: await this.call('manager', 'canDeactivate', this.profile, profile),
timestamp: Date.now()
}
this.renderComponent()
}
unlinkContent (profile: Profile) {
delete this.icons[profile.name]
this.renderComponent()
}
async activateHome() {
await this.call('manager', 'activatePlugin', 'home')
await this.call('tabs', 'focus', 'home')
}
/**
* Set an icon as active
* @param {string} name Name of profile of the module to activate
*/
select (name: string) {
// TODO: Only keep `this.emit` (issue#2210)
console.log(name, this)
this.emit('showContent', name)
this.events.emit('showContent', name)
}
/**
* Toggles the side panel for plugin
* @param {string} name Name of profile of the module to activate
*/
toggle (name: string) {
// TODO: Only keep `this.emit` (issue#2210)
this.emit('toggleContent', name)
this.events.emit('toggleContent', name)
}
render () {
return this.htmlElement
}
}

@ -50,6 +50,10 @@ export class RemixAppManager extends PluginManager {
return isNative(from.name)
}
async canDeactivate(from,to) {
return this.canDeactivatePlugin(from, to)
}
async deactivatePlugin (name) {
const [to, from] = [
await this.getProfile(name),

@ -31,7 +31,7 @@ export class WalkthroughService extends Plugin {
position: 'right'
},
{
element: document.querySelector('#compileIcons'),
element: document.querySelector('#verticalIconsKindsolidity'),
title: 'Solidity Compiler',
intro: 'Having selected a .sol file in the File Explorers (the icon above), compile it with the Solidity Compiler.',
tooltipClass: 'bg-light text-dark',

@ -35,7 +35,8 @@ export class CompilerImports extends Plugin {
isExternalUrl (url) {
const handlers = this.urlResolver.getHandlers()
return handlers.some(handler => handler.match(url))
// we filter out "npm" because this will be recognized as internal url although it's not the case.
return handlers.filter((handler) => handler.type !== 'npm').some(handler => handler.match(url))
}
/**

@ -3,10 +3,9 @@ import React from 'react'
export const fileChangedToastMsg = (from: string, path: string) => (
<div><i className="fas fa-exclamation-triangle text-danger mr-1"></i>
<span>
{from}
<span className="font-weight-bold text-warning">
{from} <span className="font-weight-bold text-warning">
is modifying
</span>{path}
</span> {path}
</span>
</div>
)
@ -52,4 +51,4 @@ export const sourceVerificationNotAvailableToastMsg = () => (
<div>
<b>Source verification plugin not activated or not available.</b> continuing <i>without</i> source code debugging.
</div>
)
)

@ -36,7 +36,7 @@
.remixui_home_rightPanel {
right: 0;
position: absolute;
z-index: 3;
z-index: 3000;
}
.remixui_home_remixHomeMedia {
overflow-y: auto;

@ -80,6 +80,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
const remiAudioEl = useRef(null)
const inputValue = useRef(null)
const rightPanel = useRef(null)
useEffect(() => {
plugin.call('theme', 'currentTheme').then((theme) => {
@ -97,7 +98,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
window.addEventListener('click', (event) => {
const target = event.target as Element
const id = target.id
if (id !== 'remixIDEHomeTwitterbtn' && id !== 'remixIDEHomeMediumbtn') {
if (id !== 'remixIDEHomeTwitterbtn' && id !== 'remixIDEHomeMediumbtn' && !rightPanel.current.contains(event.target)) {
// todo check event.target
setState(prevState => { return { ...prevState, showMediaPanel: 'none' } })
}
@ -266,7 +267,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
</p>
<p className="mb-1">
<i className="mr-2 far fa-file-alt"></i>
<label className="ml-1 remixui_home_labelIt remixui_home_bigLabelSize} remixui_home_text" htmlFor="openFileInput">
<label className="ml-1 remixui_home_labelIt remixui_home_bigLabelSize remixui_home_text" htmlFor="openFileInput">
Open Files
</label>
<input title="open file" type="file" id="openFileInput" onChange={(event) => {
@ -334,9 +335,14 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
}}
></button>
</div>
<div className="mr-3 d-flex bg-light remixui_home_panels" style={ { visibility: state.showMediaPanel === 'none' ? 'hidden' : 'visible' } } id="remixIDEMediaPanels">
<div
className="mr-3 d-flex bg-light remixui_home_panels"
style={ { visibility: state.showMediaPanel === 'none' ? 'hidden' : 'visible' } }
id="remixIDEMediaPanels"
ref={rightPanel}
>
<div id="remixIDE_MediumBlock" className="p-2 mx-1 mt-3 mb-0 remixui_home_remixHomeMedia" style={ { maxHeight: maxHeight } }>
<div id="medium-widget" className="px-3 remixui_home_media" hidden={state.showMediaPanel !== 'medium'} style={ { maxHeight: elHeight } }>
<div id="medium-widget" className="px-3 remixui_home_media" hidden={state.showMediaPanel !== 'medium'} style={ { maxHeight: '10000px' } }>
<div
id="retainable-rss-embed"
data-rss="https://medium.com/feed/remix-ide"
@ -353,7 +359,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
<div id="remixIDE_TwitterBlock" className="p-2 mx-1 mt-3 mb-0 remixui_home_remixHomeMedia" hidden={state.showMediaPanel !== 'twitter'} style={ { maxHeight: maxHeight, marginRight: '28px' } } >
<div className="remixui_home_media" style={ { minHeight: elHeight } } >
<a className="twitter-timeline"
data-width="330"
data-width="375"
data-theme={ state.themeQuality.name }
data-chrome="nofooter noheader transparent"
data-tweet-limit="18"

@ -20,7 +20,7 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => {
return (
<header className='swapitHeader'><h6 data-id='sidePanelSwapitTitle'>{plugin?.profile.displayName || plugin?.profile.name}</h6>
{plugin?.profile.documentation ? (<a href={plugin.profile.documentation} className="titleInfo" title="link to documentation" target="_blank" rel="noreferrer"><i aria-hidden="true" className="fas fa-book"></i></a>) : ''}
{plugin?.profile.documentation ? (<a href={plugin.profile.documentation} className="titleInfo mb-2" title="link to documentation" target="_blank" rel="noreferrer"><i aria-hidden="true" className="fas fa-book"></i></a>) : ''}
</header>)
}

@ -6,4 +6,4 @@ export type PluginRecord = {
active: boolean
class?: string
minimized?: boolean
}
}

@ -1,19 +1,19 @@
{
"env": {
"browser": true,
"es6": true
"browser": true,
"es6": true
},
"extends": ["../../../.eslintrc"],
"ignorePatterns": ["!**/*"],
"extends": "../../../.eslintrc.json",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 11,
"sourceType": "module"
"ecmaVersion": 11,
"sourceType": "module"
},
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error"
"standard/no-callback-literal": "off"
}
}
}

@ -1 +1,2 @@
export * from './lib/remix-ui-vertical-icons-panel'
export { default as RemixUiVerticalIconsPanel } from './lib/remix-ui-vertical-icons-panel'
export { IconRecord } from './lib/types'

@ -1,10 +1,5 @@
/* 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'
import React from 'react'
import { BadgeStatus } from './Icon'
interface BadgeProps {
badgeStatus?: BadgeStatus
@ -65,4 +60,4 @@ function Badge ({ badgeStatus }: BadgeProps) {
)
}
export default Badge
export default Badge

@ -1,5 +1,3 @@
/* eslint-disable no-use-before-define */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import React from 'react'
function BasicLogo () {

@ -3,14 +3,23 @@ import React, { MutableRefObject } from 'react'
export interface ChevronProps {
divElementRef: MutableRefObject<any>
cssRule: string
cssRule: string,
direction: string
}
function Chevron (props: ChevronProps) {
const click = () => {
if (props.direction === 'down') {
props.divElementRef.current.scrollBy({ top: 40, behavior: 'smooth' })
} else {
props.divElementRef.current.scrollBy({ top: -40, behavior: 'smooth' })
}
}
return (
<>
{ props.divElementRef.current && props.divElementRef.current.scrollHeight > props.divElementRef.current.clientHeight
? <i className={props.cssRule}></i> : null }
? <i onClick={click} className={props.cssRule}></i> : null }
</>
)
}

@ -1,41 +0,0 @@
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel'
// eslint-disable-next-line no-use-before-define
import React, { Fragment } from 'react'
import Icon from './Icon'
interface DebuggerProps {
verticalIconsPlugin: VerticalIcons
itemContextAction: (e: any, name: string, documentation: string) => Promise<void>
addActive: (name: string) => void
removeActive: () => void
}
function Debugger ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: DebuggerProps) {
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
}
/>
</div>
))
: null}
</Fragment>
)
}
export default Debugger

@ -1,59 +0,0 @@
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

@ -1,19 +1,15 @@
/* 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 React from 'react'
import BasicLogo from './BasicLogo'
interface HomeProps {
verticalIconPlugin: VerticalIcons
verticalIconPlugin: any
}
function Home ({ verticalIconPlugin }: HomeProps) {
return (
<div
className="pl-1 mt-2 remixui_homeIcon"
onClick={async () => verticalIconPlugin.activateHome()}
// @ts-ignore
plugin="home"
className="mt-3 my-1 remixui_homeIcon"
onClick={async () => await verticalIconPlugin.activateHome()}
{...{ plugin: 'home'}}
title="Home"
data-id="verticalIconsHomeIcon"
id="verticalIconsHomeIcon"

@ -1,9 +1,10 @@
import VerticalIconsContextMenu from '../vertical-icons-context-menu'
// eslint-disable-next-line no-use-before-define
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'
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer'
import { Plugin } from '@remixproject/engine'
import { IconRecord } from '../types'
export interface IconStatus {
key: string
@ -16,26 +17,11 @@ 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
}
interface IconProps {
verticalIconPlugin: VerticalIcons
profile: IconProfile
verticalIconPlugin: Plugin
iconRecord: IconRecord
contextMenuAction: (evt: any, profileName: string, documentation: string) => void
addActive: (profileName: string) => void
removeActive: () => void
theme: string
}
const initialState = {
@ -46,18 +32,15 @@ const initialState = {
pluginName: ''
}
function Icon ({
profile,
const Icon = ({
iconRecord,
verticalIconPlugin,
contextMenuAction,
addActive,
removeActive
// eslint-disable-next-line @typescript-eslint/no-unused-vars
}: IconProps) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { tooltip, displayName, name, kind, icon, documentation } = profile
theme
}: IconProps) => {
const { displayName, name, icon, documentation } = iconRecord.profile
const [title] = useState(() => {
const temp = tooltip || displayName || name
const temp = null || displayName || name
return temp.replace(/^\w/, (word: string) => word.toUpperCase())
})
const [links, setLinks] = useState<{ Documentation: string, CanDeactivate: boolean }>(
@ -71,11 +54,9 @@ function Icon ({
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 })
const deactivationState = iconRecord.canbeDeactivated
if (documentation && documentation.length > 0 && deactivationState) {
setLinks({ Documentation: documentation, CanDeactivate: deactivationState })
} else {
@ -102,21 +83,13 @@ function Icon ({
}, [])
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)
}
}}
className={`remixui_icon m-2 pl-1`}
onClick={() => {
removeActive()
addActive(name)
verticalIconPlugin.toggle(name)
(verticalIconPlugin as any).toggle(name)
}}
// @ts-ignore
plugin={name}
{...{plugin: name}}
title={title}
onContextMenu={(e: any) => {
e.preventDefault()
@ -127,11 +100,10 @@ function Icon ({
id={`verticalIconsKind${name}`}
ref={iconRef}
>
<img className="remixui_image" src={icon} alt={name} />
{ badgeStatus && badgeStatus.pluginName === name ? (
<img className={`${theme === 'dark' ? 'invert' : ''} ${theme} remixui_image ${iconRecord.active ? `selected-${theme}`:''}`} src={icon} alt={name} />
<Badge
badgeStatus={badgeStatus}
/>) : null }
/>
</div>
{showContext ? (
<VerticalIconsContextMenu
@ -145,7 +117,7 @@ function Icon ({
contextMenuAction={contextMenuAction}
/>
) : null}
</Fragment>
</>
)
}

@ -0,0 +1,33 @@
/* eslint-disable no-use-before-define */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useEffect } from 'react'
import { IconRecord } from '../types'
import Icon from './Icon'
interface OtherIconsProps {
verticalIconsPlugin: any
itemContextAction: (e: any, name: string, documentation: string) => Promise<void>
icons: IconRecord[]
theme: string
}
function IconList ({ verticalIconsPlugin, itemContextAction, icons, theme }: OtherIconsProps) {
return (
<div id="otherIcons">
{
icons
.map(p => (
<Icon
theme={theme}
iconRecord={p}
verticalIconPlugin={verticalIconsPlugin}
contextMenuAction={itemContextAction}
key={
p.profile.name
}
/>
))}
</div>
)
}
export default IconList

@ -1,43 +0,0 @@
/* 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 from 'react'
import Icon 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
}
function OtherIcons ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: OtherIconsProps) {
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
}
/>
))}
</div>
)
}
export default OtherIcons

@ -1,36 +0,0 @@
/* 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

@ -1,72 +0,0 @@
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}
/>
{
scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight
? (
<Chevron
divElementRef={scrollableRef}
cssRule={'fa fa-chevron-up remixui_icon-chevron mt-0 mb-0 ml-1 pl-3'}
/>
) : null
}
</Fragment>
)
}
export { RequiredSection }

@ -1,60 +0,0 @@
/* 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}>
{ scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight ? (<Chevron
divElementRef={scrollableRef}
cssRule={'fa fa-chevron-down remixui_icon-chevron mt-0 mb-0 ml-1 pl-3'}
/>) : null }
{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

@ -1,41 +0,0 @@
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel'
// eslint-disable-next-line no-use-before-define
import React, { Fragment } from 'react'
import Icon from './Icon'
interface SolidityProps {
verticalIconsPlugin: VerticalIcons
itemContextAction: (e: any, name: string, documentation: string) => Promise<void>
addActive: (name: string) => void
removeActive: () => void
}
function Solidity ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: SolidityProps) {
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
}
/>
</div>
))
: null}
</Fragment>
)
}
export default Solidity

@ -1,41 +0,0 @@
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel'
// eslint-disable-next-line no-use-before-define
import React, { Fragment } from 'react'
import Icon from './Icon'
interface SolidityStaticAnalysisProps {
verticalIconsPlugin: VerticalIcons
itemContextAction: (e: any, name: string, documentation: string) => Promise<void>
addActive: (name: string) => void
removeActive: () => void
}
function SolidityStaticAnalysis ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: SolidityStaticAnalysisProps) {
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
}
/>
</div>
))
: null}
</Fragment>
)
}
export default SolidityStaticAnalysis

@ -1,42 +0,0 @@
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel'
// eslint-disable-next-line no-use-before-define
import React, { Fragment } from 'react'
import Icon from './Icon'
interface UdappProps {
verticalIconsPlugin: VerticalIcons
itemContextAction: (e: any, name: string, documentation: string) => Promise<void>
addActive: (name: string) => void
removeActive: () => void
}
function Udapp ({ verticalIconsPlugin, itemContextAction, addActive, removeActive }: UdappProps) {
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
}
/>
</div>
))
: null}
</Fragment>
)
}
export default Udapp

@ -1,8 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import helper from 'apps/remix-ide/src/lib/helper'
import { checkSpecialChars } from '@remix-ui/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
@ -14,32 +11,30 @@ export type IconBadgeReducerAction = {
* @param {String} name
* @param {Object} status
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function setIconStatus (name: string, status: IconStatus) {
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
} else key = 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
} else thisType = checkSpecialChars(status.type) ? '' : status.type!
const title = checkSpecialChars(status.title) ? '' : status.title
const pluginName = status.pluginName
return { title, type: thisType, key, text, pluginName }
}
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
export function iconBadgeReducer(state: BadgeStatus, action: IconBadgeReducerAction) {
const { status } = action.payload
const setStatus = setIconStatus(action.type, status)
return setStatus
}

@ -6,7 +6,8 @@ export type actionType = {
export function verticalScrollReducer (prevState: any, actionPayload: actionType) {
if (actionPayload.type === 'resize') {
let { scrollHeight, clientHeight, scrollState } = actionPayload.payload
const { scrollHeight, clientHeight } = actionPayload.payload
let { scrollState } = actionPayload.payload
if (scrollHeight > clientHeight) scrollState = true
return { scrollHeight, clientHeight, scrollState }
}

@ -4,6 +4,10 @@
height: 42px;
cursor: pointer;
}
.remixui_homeIcon:hover {
box-shadow: 0px 0px 14px -7px;
}
.remixui_homeIcon svg path {
fill: var(--primary);
}
@ -16,13 +20,14 @@
justify-content: space-between;
align-items: center;
}
.remixui_icon:hover {
box-shadow: 0px 0px 14px -7px;
}
.remixui_icon {
cursor: pointer;
margin-bottom: 3px;
position: 12px;
width: 36px;
height: 36px;
padding: relative;
border-radius: 8px;
}
.remixui_icon img {
@ -31,6 +36,16 @@
padding: 4px;
filter: invert(0.5);
}
.remixui_icon .selected-dark {
filter: invert(1) grayscale(1);
}
.remixui_icon .selected-light {
filter: invert(0) grayscale(1);
}
.remixui_image {
}
.remixui_icon svg {
@ -116,4 +131,8 @@
#menuitems {
list-style: none;
margin: 0px;
}
.remixui_icon-chevron {
cursor: pointer;
}

@ -1,5 +1,3 @@
/* eslint-disable no-use-before-define */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, {
Fragment,
useEffect,
@ -7,16 +5,16 @@ import React, {
useRef,
useState
} from 'react'
import { Plugin } from '@remixproject/engine'
import './remix-ui-vertical-icons-panel.css'
import OtherIcons from './components/OtherIcons'
import { VerticalIcons } from '../../types/vertical-icons-panel'
import IconList from './components/IconList'
import Home from './components/Home'
import Settings from './components/Settings'
import { RequiredSection } from './components/RequiredSection'
import { verticalScrollReducer } from './reducers/verticalScrollReducer'
import { Chevron } from './components/Chevron'
import { IconRecord } from './types'
export interface RemixUiVerticalIconsPanelProps {
verticalIconsPlugin: VerticalIcons
verticalIconsPlugin: Plugin
icons: IconRecord[]
}
const initialState = {
@ -25,95 +23,54 @@ const initialState = {
scrollState: false
}
export function RemixUiVerticalIconsPanel ({
verticalIconsPlugin
}: RemixUiVerticalIconsPanelProps) {
const RemixUiVerticalIconsPanel = ({
verticalIconsPlugin, icons
}: RemixUiVerticalIconsPanelProps) => {
const scrollableRef = useRef<any>()
const iconPanelRef = useRef<any>()
const [activateScroll, dispatchScrollAction] = useReducer(verticalScrollReducer, initialState)
const [theme, setTheme] = useState<string>('dark')
useEffect(() => {
const evaluateScrollability = (evt: any) => {
dispatchScrollAction({
type: 'resize',
payload: {
scrollHeight: document.querySelector('#remixuiScrollable')?.scrollHeight,
clientHeight: document.querySelector('#remixuiScrollable')?.clientHeight,
scrollState: false
}
})
}
addEventListener('resize', evaluateScrollability)
return () => {
removeEventListener('resize', evaluateScrollability)
}
})
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)')
const evaluateScrollability = () => {
dispatchScrollAction({
type: 'resize',
payload: {
scrollHeight: scrollableRef.current?.scrollHeight,
clientHeight: scrollableRef.current?.clientHeight,
scrollState: false
}
})
// 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}%)`)
useEffect(() => {
window.addEventListener('resize', evaluateScrollability)
evaluateScrollability()
return () => {
window.removeEventListener('resize', evaluateScrollability)
}
}
}, [])
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(() => {
evaluateScrollability()
},[icons, theme])
useEffect(() => {
const themeModule = verticalIconsPlugin.registry.get('themeModule').api
themeModule.events.on('themeChanged', (theme: any) => {
onThemeChanged(theme.quality)
verticalIconsPlugin.call('theme', 'currentTheme').then((th: any) => {
setTheme(th.quality)
})
verticalIconsPlugin.on('theme', 'themeChanged', (th: any) => {
setTheme(th.quality)
})
return () => {
themeModule.events.off('themeChanged')
verticalIconsPlugin.off('theme', 'themeChanged')
}
}, [])
useEffect(() => {
if (verticalIconsPlugin.targetProfileForChange && verticalIconsPlugin.targetProfileForChange.udapp) {
const doWalkThroughEvent = new Event('doWalkThrough')
document.dispatchEvent(doWalkThroughEvent)
}
}, [Object.keys(verticalIconsPlugin.targetProfileForChange).length])
async function itemContextAction (e: any, name: string, documentation: string) {
verticalIconsPlugin.call('manager', 'deactivatePlugin', name)
}
return (
<div id="iconsP" className="h-100">
@ -121,13 +78,22 @@ export function RemixUiVerticalIconsPanel ({
<Home verticalIconPlugin={verticalIconsPlugin} />
<div className={scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight
? 'remixui_default-icons-container remixui_requiredSection' : activateScroll && activateScroll.scrollState ? 'remixui_default-icons-container remixui_requiredSection' : 'remixui_requiredSection'}>
<RequiredSection
<IconList
theme={theme}
icons={icons.filter((p) => p.isRequired && p.profile.name !== 'pluginManager')}
verticalIconsPlugin={verticalIconsPlugin}
addActive={addActive}
removeActive={removeActive}
itemContextAction={itemContextAction}
scrollableRef={scrollableRef}
/>
{
scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight
? (
<Chevron
direction='up'
divElementRef={scrollableRef}
cssRule={'fa fa-chevron-up remixui_icon-chevron mt-0 mb-0 ml-1 pl-3'}
/>
) : null
}
</div>
<div
id="remixuiScrollable"
@ -136,26 +102,29 @@ export function RemixUiVerticalIconsPanel ({
: activateScroll && activateScroll.scrollState ? 'remixui_default-icons-container remixui_scrollable-container remixui_scrollbar remixui_hide-scroll' : 'remixui_scrollable-container remixui_scrollbar remixui_hide-scroll'}
ref={scrollableRef}
>
<OtherIcons
<IconList
theme={theme}
icons={icons.filter((p) => {return !p.isRequired && p.profile.name !== 'settings'})}
verticalIconsPlugin={verticalIconsPlugin}
addActive={addActive}
removeActive={removeActive}
itemContextAction={itemContextAction}
/>
</div>
{verticalIconsPlugin.targetProfileForChange &&
Object.keys(verticalIconsPlugin.targetProfileForChange).length ? (
<Fragment>
<Settings
<div>
{ scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight ? (<Chevron
divElementRef={scrollableRef}
direction='down'
cssRule={'fa fa-chevron-down remixui_icon-chevron mt-0 mb-0 ml-1 pl-3'}
/>) : null }
<IconList
theme={theme}
icons={icons.filter((p) => p.profile.name === 'settings' || p.profile.name === 'pluginManager')}
verticalIconsPlugin={verticalIconsPlugin}
addActive={addActive}
removeActive={removeActive}
itemContextAction={itemContextAction}
scrollableRef={scrollableRef}
/>
</Fragment>
) : null}
</div>
</div>
</div>
)
}
export default RemixUiVerticalIconsPanel

@ -0,0 +1,10 @@
import { Profile } from '@remixproject/plugin-utils'
export type IconRecord = {
profile: Profile
active: boolean
class?: string
canbeDeactivated?: boolean
isRequired?: boolean
timestamp: number
}

@ -1,9 +1,5 @@
/* 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 { Plugin } from '@remixproject/engine'
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
@ -11,7 +7,7 @@ export interface VerticalIconsContextMenuProps extends React.DetailedHTMLProps<R
profileName: string
links: { Documentation: string, CanDeactivate: boolean }
canBeDeactivated: boolean
verticalIconPlugin: VerticalIcons
verticalIconPlugin: any
hideContextMenu: () => void
contextMenuAction: (evt: any, profileName: string, documentation: string) => void
}
@ -21,31 +17,22 @@ interface MenuLinksProps {
hide: () => void
profileName: string
canBeDeactivated: boolean
verticalIconPlugin: VerticalIcons
verticalIconPlugin: any
ref?: React.MutableRefObject<any>
toggle: (name: string) => void
contextMenuAction: (evt: any, profileName: string, documentation: string) => void
}
interface MenuProps {
verticalIconsPlugin: VerticalIcons
verticalIconsPlugin: Plugin
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 VerticalIconsContextMenu = (props: VerticalIconsContextMenuProps) =>{
const menuRef = useRef(null)
useEffect(() => {
document.addEventListener('click', props.hideContextMenu)
return () => document.removeEventListener('click', props.hideContextMenu)
}, [])
ClickOutside(menuRef, props.hideContextMenu)
useEffect(() => {
// @ts-ignore
menuRef.current.focus()
@ -54,7 +41,6 @@ function VerticalIconsContextMenu (props: VerticalIconsContextMenuProps) {
<div
id="menuItemsContainer"
className="p-1 remixui_verticalIconContextcontainer bg-light shadow border"
onBlur={props.hideContextMenu}
style={{
left: props.pageX,
top: props.pageY,
@ -80,15 +66,15 @@ function VerticalIconsContextMenu (props: VerticalIconsContextMenuProps) {
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function MenuForLinks ({
const MenuForLinks = ({
listItems,
hide,
profileName,
contextMenuAction
}: MenuLinksProps) {
}: MenuLinksProps) => {
return (
<Fragment>
{listItems.CanDeactivate && !requiredModules.includes(profileName)
{listItems.CanDeactivate
? <li
id="menuitemdeactivate"
onClick={(evt) => {
@ -118,4 +104,18 @@ function MenuForLinks ({
)
}
function ClickOutside(ref: React.MutableRefObject<HTMLElement>, hideFn: () => void) {
useEffect(() => {
function handleClickOutside(event: any) {
if (ref.current && !ref.current.contains(event.target)) {
hideFn()
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
}
export default VerticalIconsContextMenu

@ -1,21 +1,19 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"resolveJsonModule": true
"allowSyntheticDefaultImports": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

@ -2,8 +2,7 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": ["node"],
"resolveJsonModule": true
"types": ["node"]
},
"files": [
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",

@ -1,111 +0,0 @@
/* 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 Registry from 'apps/remix-ide/src/app/state/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')

@ -117,7 +117,7 @@ export class RemixURLResolver {
// If you don't find greeter.sol on ipfs gateway use local
// const req = 'http://localhost:8080/' + url
const response: AxiosResponse = await axios.get(req)
return { content: response.data, cleanUrl: url }
return { content: response.data, cleanUrl: url.replace('ipfs/', '') }
} catch (e) {
throw e
}

@ -260,7 +260,7 @@ describe('testRunner', () => {
const content = fs.readFileSync(__dirname + '/example_1/greeter.sol', { encoding: 'utf8'})
const expt: object = {
content: content,
cleanUrl: 'ipfs/QmcuCKyokk9Z6f65ADAADNiS2R2xCjfRkv7mYBSWDwtA7M',
cleanUrl: 'QmcuCKyokk9Z6f65ADAADNiS2R2xCjfRkv7mYBSWDwtA7M',
type: 'ipfs'
}
assert.deepEqual(results, expt)

Loading…
Cancel
Save