diff --git a/apps/remix-ide-e2e/nightwatch.ts b/apps/remix-ide-e2e/nightwatch.ts
index 2bc20e8274e..d8a111a617b 100644
--- a/apps/remix-ide-e2e/nightwatch.ts
+++ b/apps/remix-ide-e2e/nightwatch.ts
@@ -68,7 +68,13 @@ module.exports = {
desiredCapabilities: {
browserName: 'firefox',
javascriptEnabled: true,
- acceptSslCerts: true
+ acceptSslCerts: true,
+ 'moz:firefoxOptions': {
+ args: [
+ '-width=2560',
+ '-height=1440'
+ ]
+ }
}
},
@@ -78,7 +84,11 @@ module.exports = {
javascriptEnabled: true,
acceptSslCerts: true,
'moz:firefoxOptions': {
- args: ['-headless']
+ args: [
+ '-headless',
+ '-width=2560',
+ '-height=1440'
+ ]
}
}
}
diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts
index a5926bd0288..e934ae2f7b8 100644
--- a/apps/remix-ide-e2e/src/helpers/init.ts
+++ b/apps/remix-ide-e2e/src/helpers/init.ts
@@ -9,6 +9,7 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url
.switchBrowserTab(0)
.waitForElementVisible('[id="remixTourSkipbtn"]')
.click('[id="remixTourSkipbtn"]')
+ .maximizeWindow()
.fullscreenWindow(() => {
if (preloadPlugins) {
initModules(browser, () => {
diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js
index 22cc43679b7..338af4bbecc 100644
--- a/apps/remix-ide/src/app.js
+++ b/apps/remix-ide/src/app.js
@@ -2,7 +2,6 @@
import { RunTab, makeUdapp } from './app/udapp'
import { RemixEngine } from './remixEngine'
import { RemixAppManager } from './remixAppManager'
-import { MainView } from './app/panels/main-view'
import { ThemeModule } from './app/tabs/theme-module'
import { NetworkModule } from './app/tabs/network-module'
import { Web3ProviderModule } from './app/tabs/web3-provider'
@@ -11,7 +10,6 @@ import { HiddenPanel } from './app/components/hidden-panel'
import { VerticalIcons } from './app/components/vertical-icons'
import { LandingPage } from './app/ui/landing-page/landing-page'
import { MainPanel } from './app/components/main-panel'
-import { FramingService } from './framingService'
import { WalkthroughService } from './walkthroughService'
@@ -20,6 +18,7 @@ import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, Fetch
import migrateFileSystem from './migrateFileSystem'
import Registry from './app/state/registry'
import { ConfigPlugin } from './app/plugins/config'
+import { Layout } from './app/panels/layout'
import { ModalPlugin } from './app/plugins/modal'
const isElectron = require('is-electron')
@@ -50,6 +49,7 @@ const TestTab = require('./app/tabs/test-tab')
const FilePanel = require('./app/panels/file-panel')
const Editor = require('./app/editor/editor')
const Terminal = require('./app/panels/terminal')
+const { TabProxy } = require('./app/panels/tab-proxy.js')
class AppComponent {
constructor () {
@@ -67,13 +67,27 @@ class AppComponent {
// load file system
self._components.filesProviders = {}
self._components.filesProviders.browser = new FileProvider('browser')
- Registry.getInstance().put({ api: self._components.filesProviders.browser, name: 'fileproviders/browser' })
- self._components.filesProviders.localhost = new RemixDProvider(self.appManager)
- Registry.getInstance().put({ api: self._components.filesProviders.localhost, name: 'fileproviders/localhost' })
+ Registry.getInstance().put({
+ api: self._components.filesProviders.browser,
+ name: 'fileproviders/browser'
+ })
+ self._components.filesProviders.localhost = new RemixDProvider(
+ self.appManager
+ )
+ Registry.getInstance().put({
+ api: self._components.filesProviders.localhost,
+ name: 'fileproviders/localhost'
+ })
self._components.filesProviders.workspace = new WorkspaceFileProvider()
- Registry.getInstance().put({ api: self._components.filesProviders.workspace, name: 'fileproviders/workspace' })
+ Registry.getInstance().put({
+ api: self._components.filesProviders.workspace,
+ name: 'fileproviders/workspace'
+ })
- Registry.getInstance().put({ api: self._components.filesProviders, name: 'fileproviders' })
+ Registry.getInstance().put({
+ api: self._components.filesProviders,
+ name: 'fileproviders'
+ })
migrateFileSystem(self._components.filesProviders.browser)
}
@@ -83,6 +97,7 @@ class AppComponent {
// APP_MANAGER
const appManager = self.appManager
const pluginLoader = self.appManager.pluginLoader
+ self.panels = {}
self.workspace = pluginLoader.get()
self.engine = new RemixEngine()
self.engine.register(appManager)
@@ -92,8 +107,15 @@ class AppComponent {
'remix-beta.ethereum.org': 25,
'remix.ethereum.org': 23
}
- self.showMatamo = (matomoDomains[window.location.hostname] && !Registry.getInstance().get('config').api.exists('settings/matomo-analytics'))
- self.walkthroughService = new WalkthroughService(appManager, self.showMatamo)
+ self.showMatamo =
+ matomoDomains[window.location.hostname] &&
+ !Registry.getInstance()
+ .get('config')
+ .api.exists('settings/matomo-analytics')
+ self.walkthroughService = new WalkthroughService(
+ appManager,
+ self.showMatamo
+ )
const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080']
// workaround for Electron support
@@ -114,7 +136,9 @@ class AppComponent {
// ----------------- editor service ----------------------------
const editor = new Editor() // wrapper around ace editor
Registry.getInstance().put({ api: editor, name: 'editor' })
- editor.event.register('requiringToSaveCurrentfile', () => fileManager.saveCurrentFile())
+ editor.event.register('requiringToSaveCurrentfile', () =>
+ fileManager.saveCurrentFile()
+ )
// ----------------- fileManager service ----------------------------
const fileManager = new FileManager(editor, appManager)
@@ -131,7 +155,10 @@ class AppComponent {
const compilerMetadataGenerator = new CompilerMetadata()
// ----------------- compilation result service (can keep track of compilation results) ----------------------------
const compilersArtefacts = new CompilerArtefacts() // store all the compilation results (key represent a compiler name)
- Registry.getInstance().put({ api: compilersArtefacts, name: 'compilersartefacts' })
+ Registry.getInstance().put({
+ api: compilersArtefacts,
+ name: 'compilersartefacts'
+ })
// service which fetch contract artifacts from sourve-verify, put artifacts in remix and compile it
const fetchAndCompile = new FetchAndCompile()
@@ -142,19 +169,22 @@ class AppComponent {
const hardhatProvider = new HardhatProvider(blockchain)
// ----------------- convert offset to line/column service -----------
const offsetToLineColumnConverter = new OffsetToLineColumnConverter()
- Registry.getInstance().put({ api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter' })
+ Registry.getInstance().put({
+ api: offsetToLineColumnConverter,
+ name: 'offsettolinecolumnconverter'
+ })
// -------------------Terminal----------------------------------------
- makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl))
+ makeUdapp(blockchain, compilersArtefacts, domEl => terminal.logHtml(domEl))
const terminal = new Terminal(
{ appManager, blockchain },
{
- getPosition: (event) => {
+ getPosition: event => {
const limitUp = 36
const limitDown = 20
const height = window.innerHeight
- let newpos = (event.pageY < limitUp) ? limitUp : event.pageY
- newpos = (newpos < height - limitDown) ? newpos : height - limitDown
+ let newpos = event.pageY < limitUp ? limitUp : event.pageY
+ newpos = newpos < height - limitDown ? newpos : height - limitDown
return height - newpos
}
}
@@ -164,8 +194,10 @@ class AppComponent {
self.modal = new ModalPlugin()
const configPlugin = new ConfigPlugin()
+ self.layout = new Layout()
self.engine.register([
+ self.layout,
self.modal,
self.gistHandler,
configPlugin,
@@ -189,22 +221,27 @@ class AppComponent {
// LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel()
- self.mainview = new MainView(contextualListener, editor, appPanel, fileManager, appManager, terminal)
Registry.getInstance().put({ api: self.mainview, name: 'mainview' })
-
- self.engine.register([
- appPanel,
- self.mainview.tabProxy
- ])
+ const tabProxy = new TabProxy(fileManager, editor)
+ self.engine.register([appPanel, tabProxy])
// those views depend on app_manager
self.menuicons = new VerticalIcons(appManager)
self.sidePanel = new SidePanel(appManager, self.menuicons)
self.hiddenPanel = new HiddenPanel()
- const pluginManagerComponent = new PluginManagerComponent(appManager, self.engine)
+ const pluginManagerComponent = new PluginManagerComponent(
+ appManager,
+ self.engine
+ )
const filePanel = new FilePanel(appManager)
- const landingPage = new LandingPage(appManager, self.menuicons, fileManager, filePanel, contentImport)
+ const landingPage = new LandingPage(
+ appManager,
+ self.menuicons,
+ fileManager,
+ filePanel,
+ contentImport
+ )
self.settings = new SettingsTab(
Registry.getInstance().get('config').api,
editor,
@@ -222,7 +259,10 @@ class AppComponent {
])
// CONTENT VIEWS & DEFAULT PLUGINS
- const compileTab = new CompileTab(Registry.getInstance().get('config').api, Registry.getInstance().get('filemanager').api)
+ const compileTab = new CompileTab(
+ Registry.getInstance().get('config').api,
+ Registry.getInstance().get('filemanager').api
+ )
const run = new RunTab(
blockchain,
Registry.getInstance().get('config').api,
@@ -231,7 +271,6 @@ class AppComponent {
filePanel,
Registry.getInstance().get('compilersartefacts').api,
networkModule,
- self.mainview,
Registry.getInstance().get('fileproviders/browser').api
)
const analysis = new AnalysisTab()
@@ -256,6 +295,13 @@ class AppComponent {
filePanel.hardhatHandle,
filePanel.slitherHandle
])
+
+ self.layout.panels = {
+ tabs: { plugin: tabProxy, active: true },
+ editor: { plugin: editor, active: true },
+ main: { plugin: appPanel, active: false },
+ terminal: { plugin: terminal, active: true, minimized: false }
+ }
}
async activate () {
@@ -270,9 +316,9 @@ class AppComponent {
try {
self.engine.register(await self.appManager.registeredPlugins())
} catch (e) {
- console.log('couldn\'t register iframe plugins', e.message)
+ console.log("couldn't register iframe plugins", e.message)
}
-
+ await self.appManager.activatePlugin(['layout'])
await self.appManager.activatePlugin(['modal'])
await self.appManager.activatePlugin(['editor'])
await self.appManager.activatePlugin(['theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
@@ -284,48 +330,56 @@ class AppComponent {
await self.appManager.activatePlugin(['settings'])
await self.appManager.activatePlugin(['walkthrough'])
- self.appManager.on('filePanel', 'workspaceInitializationCompleted', async () => {
- await self.appManager.registerContextMenuItems()
- })
+ self.appManager.on(
+ 'filePanel',
+ 'workspaceInitializationCompleted',
+ async () => {
+ await self.appManager.registerContextMenuItems()
+ }
+ )
await self.appManager.activatePlugin(['filePanel'])
// Set workspace after initial activation
self.appManager.on('editor', 'editorMounted', () => {
if (Array.isArray(self.workspace)) {
- self.appManager.activatePlugin(self.workspace).then(async () => {
- try {
- if (params.deactivate) {
- await self.appManager.deactivatePlugin(params.deactivate.split(','))
+ self.appManager
+ .activatePlugin(self.workspace)
+ .then(async () => {
+ try {
+ if (params.deactivate) {
+ await self.appManager.deactivatePlugin(
+ params.deactivate.split(',')
+ )
+ }
+ } catch (e) {
+ console.log(e)
+ }
+ if (params.code) {
+ // if code is given in url we focus on solidity plugin
+ self.menuicons.select('solidity')
+ } else {
+ // If plugins are loaded from the URL params, we focus on the last one.
+ if (
+ self.appManager.pluginLoader.current === 'queryParams' &&
+ self.workspace.length > 0
+ ) { self.menuicons.select(self.workspace[self.workspace.length - 1]) }
}
- } catch (e) {
- console.log(e)
- }
- if (params.code) {
- // if code is given in url we focus on solidity plugin
- self.menuicons.select('solidity')
- } else {
- // If plugins are loaded from the URL params, we focus on the last one.
- if (self.appManager.pluginLoader.current === 'queryParams' && self.workspace.length > 0) self.menuicons.select(self.workspace[self.workspace.length - 1])
- }
-
- if (params.call) {
- const callDetails = params.call.split('//')
- if (callDetails.length > 1) {
- toolTip(`initiating ${callDetails[0]} ...`)
- // @todo(remove the timeout when activatePlugin is on 0.3.0)
- self.appManager.call(...callDetails).catch(console.error)
+
+ if (params.call) {
+ const callDetails = params.call.split('//')
+ if (callDetails.length > 1) {
+ toolTip(`initiating ${callDetails[0]} ...`)
+ // @todo(remove the timeout when activatePlugin is on 0.3.0)
+ self.appManager.call(...callDetails).catch(console.error)
+ }
}
- }
- }).catch(console.error)
+ })
+ .catch(console.error)
}
})
// activate solidity plugin
self.appManager.activatePlugin(['solidity', 'udapp'])
// Load and start the service who manager layout and frame
- const framingService = new FramingService(self.sidePanel, self.menuicons, self.mainview, null)
-
- if (params.embed) framingService.embed()
- framingService.start(params)
}
}
diff --git a/apps/remix-ide/src/app/components/hidden-panel.js b/apps/remix-ide/src/app/components/hidden-panel.js
deleted file mode 100644
index 77f67c6f4ca..00000000000
--- a/apps/remix-ide/src/app/components/hidden-panel.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { AbstractPanel } from './panel'
-import * as packageJson from '../../../../../package.json'
-const csjs = require('csjs-inject')
-const yo = require('yo-yo')
-
-const css = csjs`
- .pluginsContainer {
- display: none;
- }
-`
-
-const profile = {
- name: 'hiddenPanel',
- displayName: 'Hidden Panel',
- description: '',
- version: packageJson.version,
- methods: ['addView', 'removeView']
-}
-
-export class HiddenPanel extends AbstractPanel {
- constructor () {
- super(profile)
- }
-
- render () {
- return yo`
-
- ${this.view}
-
`
- }
-}
diff --git a/apps/remix-ide/src/app/components/hidden-panel.tsx b/apps/remix-ide/src/app/components/hidden-panel.tsx
new file mode 100644
index 00000000000..bfdff5a11aa
--- /dev/null
+++ b/apps/remix-ide/src/app/components/hidden-panel.tsx
@@ -0,0 +1,37 @@
+// eslint-disable-next-line no-use-before-define
+import React from 'react'
+import ReactDOM from 'react-dom' // eslint-disable-line
+import { AbstractPanel } from './panel'
+import * as packageJson from '../../../../../package.json'
+import { RemixPluginPanel } from '@remix-ui/panel'
+
+const profile = {
+ name: 'hiddenPanel',
+ displayName: 'Hidden Panel',
+ description: '',
+ version: packageJson.version,
+ methods: ['addView', 'removeView']
+}
+
+export class HiddenPanel extends AbstractPanel {
+ el: HTMLElement
+ constructor () {
+ super(profile)
+ this.el = document.createElement('div')
+ this.el.setAttribute('class', 'pluginsContainer')
+ }
+
+ addView (profile: any, view: any): void {
+ super.removeView(profile)
+ super.addView(profile, view)
+ this.renderComponent()
+ }
+
+ render () {
+ return this.el
+ }
+
+ renderComponent () {
+ ReactDOM.render(>} plugins={this.plugins}/>, this.el)
+ }
+}
diff --git a/apps/remix-ide/src/app/components/main-panel.js b/apps/remix-ide/src/app/components/main-panel.js
deleted file mode 100644
index 66e6a502450..00000000000
--- a/apps/remix-ide/src/app/components/main-panel.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { AbstractPanel } from './panel'
-import * as packageJson from '../../../../../package.json'
-const yo = require('yo-yo')
-const csjs = require('csjs-inject')
-
-const css = csjs`
- .pluginsContainer {
- height: 100%;
- display: flex;
- overflow-y: hidden;
- }
-`
-
-const profile = {
- name: 'mainPanel',
- displayName: 'Main Panel',
- description: '',
- version: packageJson.version,
- methods: ['addView', 'removeView']
-}
-
-export class MainPanel extends AbstractPanel {
- constructor () {
- super(profile)
- }
-
- focus (name) {
- this.emit('focusChanged', name)
- super.focus(name)
- }
-
- render () {
- return yo`
-
- ${this.view}
-
`
- }
-}
diff --git a/apps/remix-ide/src/app/components/main-panel.tsx b/apps/remix-ide/src/app/components/main-panel.tsx
new file mode 100644
index 00000000000..b9d180f194b
--- /dev/null
+++ b/apps/remix-ide/src/app/components/main-panel.tsx
@@ -0,0 +1,57 @@
+import React from 'react' // eslint-disable-line
+import { AbstractPanel } from './panel'
+import ReactDOM from 'react-dom' // eslint-disable-line
+import { RemixPluginPanel } from '@remix-ui/panel'
+import packageJson from '../../../../../package.json'
+
+const profile = {
+ name: 'mainPanel',
+ displayName: 'Main Panel',
+ description: '',
+ version: packageJson.version,
+ methods: ['addView', 'removeView', 'showContent']
+}
+
+export class MainPanel extends AbstractPanel {
+ element: HTMLDivElement
+ constructor (config) {
+ super(profile)
+ this.element = document.createElement('div')
+ this.element.setAttribute('data-id', 'mainPanelPluginsContainer')
+ this.element.setAttribute('style', 'height: 100%; width: 100%;')
+ // this.config = config
+ }
+
+ onActivation () {
+ this.renderComponent()
+ }
+
+ focus (name) {
+ this.emit('focusChanged', name)
+ super.focus(name)
+ this.renderComponent()
+ }
+
+ addView (profile, view) {
+ super.addView(profile, view)
+ this.renderComponent()
+ }
+
+ removeView (profile) {
+ super.removeView(profile)
+ this.renderComponent()
+ }
+
+ async showContent (name) {
+ super.showContent(name)
+ this.renderComponent()
+ }
+
+ render () {
+ return this.element
+ }
+
+ renderComponent () {
+ ReactDOM.render(>} plugins={this.plugins}/>, this.element)
+ }
+}
diff --git a/apps/remix-ide/src/app/components/panel.js b/apps/remix-ide/src/app/components/panel.js
deleted file mode 100644
index 08d9abf20fc..00000000000
--- a/apps/remix-ide/src/app/components/panel.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import { EventEmitter } from 'events'
-import { HostPlugin } from '@remixproject/engine-web'
-const csjs = require('csjs-inject')
-const yo = require('yo-yo')
-
-const css = csjs`
- .plugins {
- height: 100%;
- }
- .plugItIn {
- display : none;
- height : 100%;
- }
- .plugItIn > div {
- overflow-y : auto;
- overflow-x : hidden;
- height : 100%;
- width : 100%;
- }
- .plugItIn.active {
- display : block;
- }
- .pluginsContainer {
- height : 100%;
- overflow-y : hidden;
- }
-`
-
-/** Abstract class used for hosting the view of a plugin */
-export class AbstractPanel extends HostPlugin {
- constructor (profile) {
- super(profile)
- this.events = new EventEmitter()
- this.contents = {}
- this.active = undefined
-
- // View where the plugin HTMLElement leaves
- this.view = yo``
- }
-
- /**
- * Add the plugin to the panel
- * @param {String} name the name of the plugin
- * @param {HTMLElement} content the HTMLContent of the plugin
- */
- add (view, name) {
- if (this.contents[name]) throw new Error(`Plugin ${name} already rendered`)
- view.style.height = '100%'
- view.style.width = '100%'
- view.style.border = '0'
-
- const isIframe = view.tagName === 'IFRAME'
- view.style.display = isIframe ? 'none' : 'block'
- const loading = isIframe ? yo`
-
- ` : ''
- this.contents[name] = yo`${view}${loading}
`
-
- if (view.tagName === 'IFRAME') {
- view.addEventListener('load', () => {
- if (this.contents[name].contains(loading)) {
- this.contents[name].removeChild(loading)
- }
- view.style.display = 'block'
- })
- }
- this.contents[name].style.display = 'none'
- this.view.appendChild(this.contents[name])
- }
-
- addView (profile, view) {
- this.add(view, profile.name)
- }
-
- removeView (profile) {
- this.remove(profile.name)
- }
-
- /**
- * Remove a plugin from the panel
- * @param {String} name The name of the plugin to remove
- */
- remove (name) {
- const el = this.contents[name]
- delete this.contents[name]
- if (el) el.parentElement.removeChild(el)
- if (name === this.active) this.active = undefined
- }
-
- /**
- * Display the content of this specific plugin
- * @param {String} name The name of the plugin to display the content
- */
- showContent (name) {
- if (!this.contents[name]) throw new Error(`Plugin ${name} is not yet activated`)
- // hiding the current view and display the `moduleName`
- if (this.active) {
- this.contents[this.active].style.display = 'none'
- }
- this.contents[name].style.display = 'flex'
- this.active = name
- }
-
- focus (name) {
- this.showContent(name)
- }
-}
diff --git a/apps/remix-ide/src/app/components/panel.ts b/apps/remix-ide/src/app/components/panel.ts
new file mode 100644
index 00000000000..a5747188af2
--- /dev/null
+++ b/apps/remix-ide/src/app/components/panel.ts
@@ -0,0 +1,63 @@
+import React from 'react' // eslint-disable-line
+import { EventEmitter } from 'events'
+import { HostPlugin } from '@remixproject/engine-web' // eslint-disable-line
+import { PluginRecord } from 'libs/remix-ui/panel/src/lib/types'
+const EventManager = require('../../lib/events')
+
+export class AbstractPanel extends HostPlugin {
+ events: EventEmitter
+ event: any
+ public plugins: Record = {}
+ constructor (profile) {
+ super(profile)
+ this.events = new EventEmitter()
+ this.event = new EventManager()
+ }
+
+ currentFocus (): string {
+ return Object.values(this.plugins).find(plugin => {
+ return plugin.active
+ }).profile.name
+ }
+
+ addView (profile, view) {
+ if (this.plugins[profile.name]) throw new Error(`Plugin ${profile.name} already rendered`)
+ this.plugins[profile.name] = {
+ profile: profile,
+ view: view,
+ active: false,
+ class: 'plugItIn active'
+ }
+ }
+
+ removeView (profile) {
+ this.emit('pluginDisabled', profile.name)
+ this.call('menuicons', 'unlinkContent', profile)
+ this.remove(profile.name)
+ }
+
+ /**
+ * Remove a plugin from the panel
+ * @param {String} name The name of the plugin to remove
+ */
+ remove (name) {
+ delete this.plugins[name]
+ }
+
+ /**
+ * Display the content of this specific plugin
+ * @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`)
+
+ Object.values(this.plugins).forEach(plugin => {
+ plugin.active = false
+ })
+ this.plugins[name].active = true
+ }
+
+ focus (name) {
+ this.showContent(name)
+ }
+}
diff --git a/apps/remix-ide/src/app/components/side-panel.js b/apps/remix-ide/src/app/components/side-panel.js
deleted file mode 100644
index 0cc09d84d4e..00000000000
--- a/apps/remix-ide/src/app/components/side-panel.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import { AbstractPanel } from './panel'
-import * as packageJson from '../../../../../package.json'
-const csjs = require('csjs-inject')
-const yo = require('yo-yo')
-
-const css = csjs`
- .panel {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- flex: auto;
- }
- .swapitTitle {
- margin: 0;
- text-transform: uppercase;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- .swapitTitle i{
- padding-left: 6px;
- font-size: 14px;
- }
- .swapitHeader {
- display: flex;
- align-items: center;
- padding: 16px 24px 15px;
- justify-content: space-between;
- }
- .icons i {
- height: 80%;
- cursor: pointer;
- }
- .pluginsContainer {
- height: 100%;
- overflow-y: auto;
- }
- .titleInfo {
- padding-left: 10px;
- }
- .versionBadge {
- background-color: var(--light);
- padding: 0 7px;
- font-weight: bolder;
- margin-left: 5px;
- text-transform: lowercase;
- cursor: default;
- }
-`
-
-const sidePanel = {
- name: 'sidePanel',
- displayName: 'Side Panel',
- description: '',
- version: packageJson.version,
- methods: ['addView', 'removeView']
-}
-
-// TODO merge with vertical-icons.js
-export class SidePanel extends AbstractPanel {
- constructor (appManager, verticalIcons) {
- super(sidePanel)
- this.appManager = appManager
- this.header = yo``
- this.renderHeader()
- this.verticalIcons = verticalIcons
-
- // Toggle content
- verticalIcons.events.on('toggleContent', (name) => {
- if (!this.contents[name]) return
- if (this.active === name) {
- // TODO: Only keep `this.emit` (issue#2210)
- this.emit('toggle', name)
- this.events.emit('toggle', name)
- return
- }
- this.showContent(name)
- // TODO: Only keep `this.emit` (issue#2210)
- this.emit('showing', name)
- this.events.emit('showing', name)
- })
- // Force opening
- verticalIcons.events.on('showContent', (name) => {
- if (!this.contents[name]) return
- this.showContent(name)
- // TODO: Only keep `this.emit` (issue#2210)
- this.emit('showing', name)
- this.events.emit('showing', name)
- })
- }
-
- focus (name) {
- this.emit('focusChanged', name)
- super.focus(name)
- }
-
- removeView (profile) {
- super.removeView(profile)
- this.emit('pluginDisabled', profile.name)
- this.verticalIcons.unlinkContent(profile)
- }
-
- addView (profile, view) {
- super.addView(profile, view)
- this.verticalIcons.linkContent(profile)
- }
-
- /**
- * Display content and update the header
- * @param {String} name The name of the plugin to display
- */
- async showContent (name) {
- super.showContent(name)
- this.renderHeader()
- this.emit('focusChanged', name)
- }
-
- /** The header of the side panel */
- async renderHeader () {
- let name = ' - '
- let docLink = ''
- let versionWarning
- if (this.active) {
- const profile = await this.appManager.getProfile(this.active)
- name = profile.displayName ? profile.displayName : profile.name
- docLink = profile.documentation ? yo`` : ''
- if (profile.version && profile.version.match(/\b(\w*alpha\w*)\b/g)) {
- versionWarning = yo`alpha`
- }
- // Beta
- if (profile.version && profile.version.match(/\b(\w*beta\w*)\b/g)) {
- versionWarning = yo`beta`
- }
- }
-
- const header = yo`
-
- `
- yo.update(this.header, header)
- }
-
- render () {
- return yo`
-
- ${this.header}
-
- ${this.view}
-
- `
- }
-}
diff --git a/apps/remix-ide/src/app/components/side-panel.tsx b/apps/remix-ide/src/app/components/side-panel.tsx
new file mode 100644
index 00000000000..8b64d64e451
--- /dev/null
+++ b/apps/remix-ide/src/app/components/side-panel.tsx
@@ -0,0 +1,95 @@
+// eslint-disable-next-line no-use-before-define
+import React from 'react'
+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')
+
+const sidePanel = {
+ name: 'sidePanel',
+ displayName: 'Side Panel',
+ description: '',
+ version: packageJson.version,
+ 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) {
+ super(sidePanel)
+ this.appManager = appManager
+ this.sideelement = document.createElement('section')
+ this.sideelement.setAttribute('class', 'panel plugin-manager')
+ this.verticalIcons = verticalIcons
+
+ // Toggle content
+ verticalIcons.events.on('toggleContent', (name) => {
+ if (!this.plugins[name]) return
+ if (this.plugins[name].active) {
+ // TODO: Only keep `this.emit` (issue#2210)
+ this.emit('toggle', name)
+ this.events.emit('toggle', name)
+ return
+ }
+ this.showContent(name)
+ // TODO: Only keep `this.emit` (issue#2210)
+ this.emit('showing', name)
+ this.events.emit('showing', name)
+ })
+ // Force opening
+ verticalIcons.events.on('showContent', (name) => {
+ if (!this.plugins[name]) return
+ this.showContent(name)
+ // TODO: Only keep `this.emit` (issue#2210)
+ this.emit('showing', name)
+ this.events.emit('showing', name)
+ })
+ }
+
+ onActivation () {
+ this.renderComponent()
+ }
+
+ focus (name) {
+ this.emit('focusChanged', name)
+ super.focus(name)
+ }
+
+ removeView (profile) {
+ super.removeView(profile)
+ this.emit('pluginDisabled', profile.name)
+ this.call('menuicons', 'unlinkContent', profile)
+ this.renderComponent()
+ }
+
+ addView (profile, view) {
+ super.addView(profile, view)
+ this.verticalIcons.linkContent(profile)
+ this.renderComponent()
+ }
+
+ /**
+ * Display content and update the header
+ * @param {String} name The name of the plugin to display
+ */
+ async showContent (name) {
+ super.showContent(name)
+ this.emit('focusChanged', name)
+ this.renderComponent()
+ }
+
+ render () {
+ return this.sideelement
+ }
+
+ renderComponent () {
+ ReactDOM.render(} plugins={this.plugins}/>, this.sideelement)
+ }
+}
diff --git a/apps/remix-ide/src/app/components/vertical-icons.js b/apps/remix-ide/src/app/components/vertical-icons.js
index cd86b1d796a..69f61329396 100644
--- a/apps/remix-ide/src/app/components/vertical-icons.js
+++ b/apps/remix-ide/src/app/components/vertical-icons.js
@@ -15,7 +15,7 @@ const profile = {
displayName: 'Vertical Icons',
description: '',
version: packageJson.version,
- methods: ['select']
+ methods: ['select', 'unlinkContent']
}
// TODO merge with side-panel.js. VerticalIcons should not be a plugin
diff --git a/apps/remix-ide/src/app/panels/layout.ts b/apps/remix-ide/src/app/panels/layout.ts
new file mode 100644
index 00000000000..451c2aefe70
--- /dev/null
+++ b/apps/remix-ide/src/app/panels/layout.ts
@@ -0,0 +1,94 @@
+import { Plugin } from '@remixproject/engine'
+import { Profile } from '@remixproject/plugin-utils'
+import { EventEmitter } from 'events'
+import QueryParams from '../../lib/query-params'
+
+const profile: Profile = {
+ name: 'layout',
+ description: 'layout',
+ methods: ['minimize']
+}
+
+interface panelState {
+ active: boolean
+ plugin: Plugin
+ minimized: boolean
+}
+interface panels {
+ tabs: panelState
+ editor: panelState
+ main: panelState
+ terminal: panelState
+}
+
+export class Layout extends Plugin {
+ event: any
+ panels: panels
+ constructor () {
+ super(profile)
+ this.event = new EventEmitter()
+ }
+
+ async onActivation (): Promise {
+ this.on('fileManager', 'currentFileChanged', () => {
+ this.panels.editor.active = true
+ this.panels.main.active = false
+ this.event.emit('change', null)
+ })
+ this.on('tabs', 'openFile', () => {
+ this.panels.editor.active = true
+ this.panels.main.active = false
+ this.event.emit('change', null)
+ })
+ this.on('tabs', 'switchApp', (name: string) => {
+ this.call('mainPanel', 'showContent', name)
+ this.panels.editor.active = false
+ this.panels.main.active = true
+ this.event.emit('change', null)
+ })
+ this.on('tabs', 'closeApp', (name: string) => {
+ this.panels.editor.active = true
+ this.panels.main.active = false
+ this.event.emit('change', null)
+ })
+ this.on('tabs', 'tabCountChanged', async count => {
+ if (!count) await this.call('manager', 'activatePlugin', 'home')
+ })
+ this.on('manager', 'activate', (profile: Profile) => {
+ switch (profile.name) {
+ case 'filePanel':
+ this.call('menuicons', 'select', 'filePanel')
+ break
+ }
+ })
+ document.addEventListener('keypress', e => {
+ if (e.shiftKey && e.ctrlKey) {
+ if (e.code === 'KeyF') {
+ // Ctrl+Shift+F
+ this.call('menuicons', 'select', 'filePanel')
+ } else if (e.code === 'KeyA') {
+ // Ctrl+Shift+A
+ this.call('menuicons', 'select', 'pluginManager')
+ } else if (e.code === 'KeyS') {
+ // Ctrl+Shift+S
+ this.call('menuicons', 'select', 'settings')
+ }
+ e.preventDefault()
+ }
+ })
+ const queryParams = new QueryParams()
+ const params = queryParams.get()
+ if (params.minimizeterminal || params.embed) {
+ this.panels.terminal.minimized = true
+ this.event.emit('change', null)
+ }
+ if (params.minimizesidepanel || params.embed) {
+ this.event.emit('minimizesidepanel')
+ }
+ }
+
+ minimize (name: string, minimized:boolean): void {
+ this.panels[name].minimized = minimized
+ this.event.emit('change', null)
+ }
+}
diff --git a/apps/remix-ide/src/app/panels/main-view.js b/apps/remix-ide/src/app/panels/main-view.js
deleted file mode 100644
index bf3a07a35b5..00000000000
--- a/apps/remix-ide/src/app/panels/main-view.js
+++ /dev/null
@@ -1,204 +0,0 @@
-import Registry from '../state/registry'
-
-var yo = require('yo-yo')
-var EventManager = require('../../lib/events')
-
-var { TabProxy } = require('./tab-proxy.js')
-
-var csjs = require('csjs-inject')
-
-var css = csjs`
- .mainview {
- display : flex;
- flex-direction : column;
- height : 100%;
- width : 100%;
- }
-`
-
-// @todo(#650) Extract this into two classes: MainPanel (TabsProxy + Iframe/Editor) & BottomPanel (Terminal)
-export class MainView {
- constructor (contextualListener, editor, mainPanel, fileManager, appManager, terminal) {
- var self = this
- self.event = new EventManager()
- self._view = {}
- self._components = {}
- self._components.registry = Registry.getInstance()
- self.contextualListener = contextualListener
- self.editor = editor
- self.fileManager = fileManager
- self.mainPanel = mainPanel
- self.txListener = Registry.getInstance().get('txlistener').api
- self._components.terminal = terminal
- this.appManager = appManager
- this.init()
- }
-
- showApp (name) {
- this.fileManager.unselectCurrentFile()
- this.mainPanel.showContent(name)
- this._view.editor.style.display = 'none'
- this._view.mainPanel.style.display = 'block'
- }
-
- getAppPanel () {
- return this.mainPanel
- }
-
- init () {
- var self = this
- self._deps = {
- config: self._components.registry.get('config').api,
- fileManager: self._components.registry.get('filemanager').api
- }
-
- self.tabProxy = new TabProxy(self.fileManager, self.editor)
- /*
- We listen here on event from the tab component to display / hide the editor and mainpanel
- depending on the content that should be displayed
- */
- self.fileManager.events.on('currentFileChanged', (file) => {
- // we check upstream for "fileChanged"
- self._view.editor.style.display = 'block'
- self._view.mainPanel.style.display = 'none'
- })
- self.tabProxy.event.on('openFile', (file) => {
- self._view.editor.style.display = 'block'
- self._view.mainPanel.style.display = 'none'
- })
- self.tabProxy.event.on('closeFile', (file) => {
- })
- self.tabProxy.event.on('switchApp', self.showApp.bind(self))
- self.tabProxy.event.on('closeApp', (name) => {
- self._view.editor.style.display = 'block'
- self._view.mainPanel.style.display = 'none'
- })
- self.tabProxy.event.on('tabCountChanged', (count) => {
- if (!count) this.editor.displayEmptyReadOnlySession()
- })
- self.data = {
- _layout: {
- top: {
- offset: self._terminalTopOffset(),
- show: true
- }
- }
- }
-
- self._components.terminal.event.register('resize', delta => self._adjustLayout('top', delta))
- if (self.txListener) {
- self._components.terminal.event.register('listenOnNetWork', (listenOnNetWork) => {
- self.txListener.setListenOnNetwork(listenOnNetWork)
- })
- }
- }
-
- _terminalTopOffset () {
- return this._deps.config.get('terminal-top-offset') || 150
- }
-
- _adjustLayout (direction, delta) {
- var limitUp = 0
- var limitDown = 32
- var containerHeight = window.innerHeight - limitUp // - menu bar containerHeight
- var self = this
- var layout = self.data._layout[direction]
- if (layout) {
- if (delta === undefined) {
- layout.show = !layout.show
- if (layout.show) delta = layout.offset
- else delta = 0
- } else {
- layout.show = true
- self._deps.config.set(`terminal-${direction}-offset`, delta)
- layout.offset = delta
- }
- }
- var tmp = delta - limitDown
- delta = tmp > 0 ? tmp : 0
- if (direction === 'top') {
- var mainPanelHeight = containerHeight - delta
- mainPanelHeight = mainPanelHeight < 0 ? 0 : mainPanelHeight
- self._view.editor.style.height = `${mainPanelHeight}px`
- self._view.mainPanel.style.height = `${mainPanelHeight}px`
- self._view.terminal.style.height = `${delta}px` // - menu bar height
- self.editor.resize((document.querySelector('#editorWrap') || {}).checked)
- self._components.terminal.scroll2bottom()
- }
- }
-
- minimizeTerminal () {
- this._adjustLayout('top')
- }
-
- showTerminal (offset) {
- this._adjustLayout('top', offset || this._terminalTopOffset())
- }
-
- getTerminal () {
- return this._components.terminal
- }
-
- getEditor () {
- var self = this
- return self.editor
- }
-
- refresh () {
- var self = this
- self._view.tabs.onmouseenter()
- }
-
- log (data = {}) {
- var self = this
- var command = self._components.terminal.commands[data.type]
- if (typeof command === 'function') command(data.value)
- }
-
- logMessage (msg) {
- var self = this
- self.log({ type: 'log', value: msg })
- }
-
- logHtmlMessage (msg) {
- var self = this
- self.log({ type: 'html', value: msg })
- }
-
- render () {
- var self = this
- if (self._view.mainview) return self._view.mainview
- self._view.editor = self.editor.render()
- self._view.editor.style.display = 'none'
- self._view.mainPanel = self.mainPanel.render()
- self._view.terminal = self._components.terminal.render()
-
- self._view.mainview = yo`
-
- ${self.tabProxy.renderTabsbar()}
- ${self._view.editor}
- ${self._view.mainPanel}
-
- ${self._view.terminal}
-
- `
-
- // INIT
- self._adjustLayout('top', self.data._layout.top.offset)
-
- document.addEventListener('keydown', (e) => {
- if (e.altKey && e.keyCode === 84) self.tabProxy.switchNextTab() // alt + t
- })
-
- return self._view.mainview
- }
-
- registerCommand (name, command, opts) {
- var self = this
- return self._components.terminal.registerCommand(name, command, opts)
- }
-
- updateTerminalFilter (filter) {
- this._components.terminal.updateJournal(filter)
- }
-}
diff --git a/apps/remix-ide/src/app/panels/tab-proxy.js b/apps/remix-ide/src/app/panels/tab-proxy.js
index 5b65254830e..267b54d8533 100644
--- a/apps/remix-ide/src/app/panels/tab-proxy.js
+++ b/apps/remix-ide/src/app/panels/tab-proxy.js
@@ -22,6 +22,7 @@ export class TabProxy extends Plugin {
this._view = {}
this._handlers = {}
this.loadedTabs = []
+ this.el = document.createElement('div')
}
onActivation () {
@@ -72,10 +73,12 @@ export class TabProxy extends Plugin {
this.addTab(workspacePath, '', () => {
this.fileManager.open(file)
this.event.emit('openFile', file)
+ this.emit('openFile', file)
},
() => {
this.fileManager.closeFile(file)
this.event.emit('closeFile', file)
+ this.emit('closeFile', file)
})
this.tabsApi.activateTab(workspacePath)
} else {
@@ -88,10 +91,12 @@ export class TabProxy extends Plugin {
this.addTab(path, '', () => {
this.fileManager.open(file)
this.event.emit('openFile', file)
+ this.emit('openFile', file)
},
() => {
this.fileManager.closeFile(file)
this.event.emit('closeFile', file)
+ this.emit('closeFile', file)
})
this.tabsApi.activateTab(path)
}
@@ -132,9 +137,9 @@ export class TabProxy extends Plugin {
this.addTab(
name,
displayName,
- () => this.event.emit('switchApp', name),
+ () => this.emit('switchApp', name),
() => {
- this.event.emit('closeApp', name)
+ this.emit('closeApp', name)
this.call('manager', 'deactivatePlugin', name)
},
icon
@@ -149,7 +154,7 @@ export class TabProxy extends Plugin {
}
focus (name) {
- this.event.emit('switchApp', name)
+ this.emit('switchApp', name)
this.tabsApi.activateTab(name)
}
@@ -199,6 +204,7 @@ export class TabProxy extends Plugin {
() => {
this.fileManager.closeFile(newName)
this.event.emit('closeFile', newName)
+ this.emit('closeFile', newName)
})
this.removeTab(oldName)
}
@@ -285,7 +291,7 @@ export class TabProxy extends Plugin {
if (this.loadedTabs[index]) {
const name = this.loadedTabs[index].name
if (this._handlers[name]) this._handlers[name].switchTo()
- this.event.emit('tabCountChanged', this.loadedTabs.length)
+ this.emit('tabCountChanged', this.loadedTabs.length)
}
}
@@ -293,7 +299,7 @@ export class TabProxy extends Plugin {
if (this.loadedTabs[index]) {
const name = this.loadedTabs[index].name
if (this._handlers[name]) this._handlers[name].close()
- this.event.emit('tabCountChanged', this.loadedTabs.length)
+ this.emit('tabCountChanged', this.loadedTabs.length)
}
}
@@ -308,8 +314,6 @@ export class TabProxy extends Plugin {
}
renderTabsbar () {
- this.el = document.createElement('div')
- this.renderComponent()
return this.el
}
}
diff --git a/apps/remix-ide/src/app/panels/terminal.js b/apps/remix-ide/src/app/panels/terminal.js
index 272284c53cd..6309327cb69 100644
--- a/apps/remix-ide/src/app/panels/terminal.js
+++ b/apps/remix-ide/src/app/panels/terminal.js
@@ -20,7 +20,7 @@ function register (api) { KONSOLES.push(api) }
const profile = {
displayName: 'Terminal',
name: 'terminal',
- methods: ['log'],
+ methods: ['log', 'logHtml'],
events: [],
description: ' - ',
version: packageJson.version
diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js
index b966287690d..48f5484979d 100644
--- a/apps/remix-ide/src/app/udapp/run-tab.js
+++ b/apps/remix-ide/src/app/udapp/run-tab.js
@@ -34,14 +34,14 @@ const profile = {
}
export class RunTab extends ViewPlugin {
- constructor (blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, mainView, fileProvider) {
+ constructor (blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider) {
super(profile)
this.event = new EventManager()
this.config = config
this.blockchain = blockchain
this.fileManager = fileManager
this.editor = editor
- this.logCallback = (msg) => { mainView.getTerminal().logHtml(yo`${msg}
`) }
+ this.logCallback = (msg) => { this.call('terminal', 'logHtml', yo`${msg}
`) }
this.filePanel = filePanel
this.compilersArtefacts = compilersArtefacts
this.networkModule = networkModule
diff --git a/apps/remix-ide/src/framingService.js b/apps/remix-ide/src/framingService.js
deleted file mode 100644
index ed029b7a65c..00000000000
--- a/apps/remix-ide/src/framingService.js
+++ /dev/null
@@ -1,34 +0,0 @@
-export class FramingService {
- constructor (sidePanel, verticalIcons, mainView, resizeFeature) {
- this.sidePanel = sidePanel
- this.verticalIcons = verticalIcons
- this.mainPanel = mainView.getAppPanel()
- this.mainView = mainView
- this.resizeFeature = resizeFeature
- }
-
- start (params) {
- this.verticalIcons.select('filePanel')
-
- document.addEventListener('keypress', (e) => {
- if (e.shiftKey && e.ctrlKey) {
- if (e.code === 'KeyF') { // Ctrl+Shift+F
- this.verticalIcons.select('filePanel')
- } else if (e.code === 'KeyA') { // Ctrl+Shift+A
- this.verticalIcons.select('pluginManager')
- } else if (e.code === 'KeyS') { // Ctrl+Shift+S
- this.verticalIcons.select('settings')
- }
- e.preventDefault()
- }
- })
-
- if (params.minimizeterminal) this.mainView.minimizeTerminal()
- if (params.minimizesidepanel) this.resizeFeature.hidePanel()
- }
-
- embed () {
- this.mainView.minimizeTerminal()
- this.resizeFeature.hidePanel()
- }
-}
diff --git a/apps/remix-ide/src/lib/panels-resize.js b/apps/remix-ide/src/lib/panels-resize.js
deleted file mode 100644
index 157535a8695..00000000000
--- a/apps/remix-ide/src/lib/panels-resize.js
+++ /dev/null
@@ -1,88 +0,0 @@
-const yo = require('yo-yo')
-const csjs = require('csjs-inject')
-
-const css = csjs`
- .dragbar {
- width : 2px;
- height : 100%;
- cursor : col-resize;
- z-index : 999;
- }
- .ghostbar {
- width : 3px;
- background-color : var(--primary);
- opacity : 0.5;
- position : absolute;
- cursor : col-resize;
- z-index : 9999;
- top : 0;
- bottom : 0;
- }
-`
-
-export default class PanelsResize {
- constructor (panel) {
- this.panel = panel
- const string = panel.style.minWidth
- this.minWidth = string.length > 2 ? parseInt(string.substring(0, string.length - 2)) : 0
- }
-
- render () {
- this.ghostbar = yo``
-
- const mousedown = (event) => {
- event.preventDefault()
- if (event.which === 1) {
- moveGhostbar(event)
- document.body.appendChild(this.ghostbar)
- document.addEventListener('mousemove', moveGhostbar)
- document.addEventListener('mouseup', removeGhostbar)
- document.addEventListener('keydown', cancelGhostbar)
- }
- }
-
- const cancelGhostbar = (event) => {
- if (event.keyCode === 27) {
- document.body.removeChild(this.ghostbar)
- document.removeEventListener('mousemove', moveGhostbar)
- document.removeEventListener('mouseup', removeGhostbar)
- document.removeEventListener('keydown', cancelGhostbar)
- }
- }
-
- const moveGhostbar = (event) => {
- this.ghostbar.style.left = event.x + 'px'
- }
-
- const removeGhostbar = (event) => {
- document.body.removeChild(this.ghostbar)
- document.removeEventListener('mousemove', moveGhostbar)
- document.removeEventListener('mouseup', removeGhostbar)
- document.removeEventListener('keydown', cancelGhostbar)
- this.setPosition(event)
- }
-
- return yo``
- }
-
- calculatePanelWidth (event) {
- return event.x - this.panel.offsetLeft
- }
-
- setPosition (event) {
- const panelWidth = this.calculatePanelWidth(event)
- // close the panel if the width is less than a minWidth
- if (panelWidth > this.minWidth - 10 || this.panel.style.display === 'none') {
- this.panel.style.width = panelWidth + 'px'
- this.showPanel()
- } else this.hidePanel()
- }
-
- hidePanel () {
- this.panel.style.display = 'none'
- }
-
- showPanel () {
- this.panel.style.display = 'flex'
- }
-}
diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js
index 74410cadf0a..5f5fa2f8eb6 100644
--- a/apps/remix-ide/src/remixAppManager.js
+++ b/apps/remix-ide/src/remixAppManager.js
@@ -1,20 +1,20 @@
/* global localStorage, fetch */
import { PluginManager } from '@remixproject/engine'
-import { IframePlugin } from '@remixproject/engine-web'
import { EventEmitter } from 'events'
import QueryParams from './lib/query-params'
import { PermissionHandler } from './app/ui/persmission-handler'
+import { IframePlugin } from '@remixproject/engine-web'
const _paq = window._paq = window._paq || []
const requiredModules = [ // services + layout views + system views
'manager', 'config', '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', 'gistHandler']
+ 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic', 'gistHandler', 'layout', 'modal']
const dependentModules = ['git', 'hardhat', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)
export function isNative (name) {
- const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting']
+ const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'modal']
return nativePlugins.includes(name) || requiredModules.includes(name)
}
@@ -78,6 +78,7 @@ export class RemixAppManager extends PluginManager {
onPluginActivated (plugin) {
this.pluginLoader.set(plugin, this.actives)
this.event.emit('activate', plugin)
+ this.emit('activate', plugin)
if (!requiredModules.includes(plugin.name)) _paq.push(['trackEvent', 'pluginManager', 'activate', plugin.name])
}
@@ -131,6 +132,7 @@ export class RemixAppManager extends PluginManager {
}
return plugins.map(plugin => {
return new IframePlugin(plugin)
+ // return new IframeReactPlugin(plugin)
})
}
diff --git a/apps/remix-ide/tsconfig.json b/apps/remix-ide/tsconfig.json
index 052537730e5..04d219a926b 100644
--- a/apps/remix-ide/tsconfig.json
+++ b/apps/remix-ide/tsconfig.json
@@ -4,6 +4,7 @@
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
+ "resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"types": ["node", "jest"],
"module": "es6",
diff --git a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.css b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.css
index a423dd6605b..1330c1179c0 100644
--- a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.css
+++ b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.css
@@ -1,26 +1,27 @@
/* dragbar UI */
-.dragbar {
- display : block;
- height : 100%;
- position : absolute;
- left: 0px;
- top: 0px;
- width: 0.3em;
- z-index: 9999;
- }
-
- .overlay {
- position: absolute;
- left: 0;
- top: 0;
- width: 100vw;
- height: 100vh;
- display: block;
- z-index: 9998;
- }
-
- .dragbar:hover, .dragbar.ondrag{
- background-color: var(--secondary);
- cursor:col-resize;
- }
\ No newline at end of file
+.dragbar {
+ display: block;
+ height: 100%;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 0.3em;
+ z-index: 9999;
+}
+
+.overlay {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ display: block;
+ z-index: 9998;
+}
+
+.dragbar:hover,
+.dragbar.ondrag {
+ background-color: var(--secondary);
+ cursor: col-resize;
+}
diff --git a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
index 29c4eeda6bc..429e49f6388 100644
--- a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
+++ b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
@@ -15,18 +15,23 @@ const DragBar = (props: IRemixDragBarUi) => {
const [offset, setOffSet] = useState(0)
const nodeRef = React.useRef(null) // fix for strictmode
- useEffect(() => {
- // arbitrary time out to wait the the UI to be completely done
- setTimeout(() => {
- setOffSet(props.refObject.current.offsetLeft)
- setDragBarPosX(offset + props.refObject.current.offsetWidth)
- }, 1000)
- }, [])
-
useEffect(() => {
setDragBarPosX(offset + (props.hidden ? 0 : props.refObject.current.offsetWidth))
}, [props.hidden, offset])
+ const handleResize = () => {
+ setOffSet(props.refObject.current.offsetLeft)
+ setDragBarPosX(props.refObject.current.offsetLeft + props.refObject.current.offsetWidth)
+ }
+
+ useEffect(() => {
+ window.addEventListener('resize', handleResize)
+ // TODO: not a good way to wait on the ref doms element to be rendered of course
+ setTimeout(() =>
+ handleResize(), 2000)
+ return () => window.removeEventListener('resize', handleResize)
+ }, [])
+
function stopDrag (e: MouseEvent, data: any) {
setDragState(false)
if (data.x < props.minWidth) {
diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
index e86e4ed63db..27d5a7b832d 100644
--- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
+++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
@@ -1,5 +1,6 @@
import React, { useEffect, useRef, useState } from 'react'
import './style/remix-app.css'
+import { RemixUIMainPanel } from '@remix-ui/panel'
import RemixSplashScreen from './components/splashscreen'
import MatomoDialog from './components/modals/matomo'
import OriginWarning from './components/modals/origin-warning'
@@ -62,6 +63,13 @@ const RemixApp = (props: IRemixAppUi) => {
props.app.sidePanel.events.on('showing', () => {
setHideSidePanel(false)
})
+
+ props.app.layout.event.on('minimizesidepanel', () => {
+ // the 'showing' event always fires from sidepanel, so delay this a bit
+ setTimeout(() => {
+ setHideSidePanel(true)
+ }, 1000)
+ })
}
const components = {
@@ -75,7 +83,8 @@ const RemixApp = (props: IRemixAppUi) => {
settings: props.app.settings,
showMatamo: props.app.showMatamo,
appManager: props.app.appManager,
- modal: props.app.modal
+ modal: props.app.modal,
+ layout: props.app.layout
}
return (
@@ -88,8 +97,9 @@ const RemixApp = (props: IRemixAppUi) => {
{components.iconPanel}
{components.sidePanel}
- {components.mainPanel}
-
+
+
+
{components.hiddenPanel}
diff --git a/libs/remix-ui/panel/.babelrc b/libs/remix-ui/panel/.babelrc
new file mode 100644
index 00000000000..64a37486919
--- /dev/null
+++ b/libs/remix-ui/panel/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": ["@nrwl/react/babel"],
+ "plugins": []
+}
\ No newline at end of file
diff --git a/libs/remix-ui/panel/.eslintrc.json b/libs/remix-ui/panel/.eslintrc.json
new file mode 100644
index 00000000000..5a1c541d113
--- /dev/null
+++ b/libs/remix-ui/panel/.eslintrc.json
@@ -0,0 +1,18 @@
+{
+ "extends": ["plugin:@nrwl/nx/react", "../../../.eslintrc"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.ts", "*.tsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.js", "*.jsx"],
+ "rules": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libs/remix-ui/panel/README.md b/libs/remix-ui/panel/README.md
new file mode 100644
index 00000000000..fa765fcb391
--- /dev/null
+++ b/libs/remix-ui/panel/README.md
@@ -0,0 +1,7 @@
+# remix-ui-side-panel
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test remix-ui-side-panel` to execute the unit tests via [Jest](https://jestjs.io).
diff --git a/libs/remix-ui/panel/src/index.ts b/libs/remix-ui/panel/src/index.ts
new file mode 100644
index 00000000000..c61d9612f13
--- /dev/null
+++ b/libs/remix-ui/panel/src/index.ts
@@ -0,0 +1,2 @@
+export { default as RemixPluginPanel } from './lib/plugins/remix-ui-panel'
+export { default as RemixUIMainPanel } from './lib/main/main-panel'
diff --git a/libs/remix-ui/panel/src/lib/dragbar/dragbar.css b/libs/remix-ui/panel/src/lib/dragbar/dragbar.css
new file mode 100644
index 00000000000..1ad9f9de856
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/dragbar/dragbar.css
@@ -0,0 +1,27 @@
+/* dragbar UI */
+
+.dragbar_terminal {
+ display: block;
+ width: 100%;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ height: 0.3em;
+ z-index: 9999;
+}
+
+.overlay {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ display: block;
+ z-index: 900;
+}
+
+.dragbar_terminal:hover,
+.dragbar_terminal.ondrag {
+ background-color: var(--secondary);
+ cursor: row-resize;
+}
diff --git a/libs/remix-ui/panel/src/lib/dragbar/dragbar.tsx b/libs/remix-ui/panel/src/lib/dragbar/dragbar.tsx
new file mode 100644
index 00000000000..232f23ff10d
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/dragbar/dragbar.tsx
@@ -0,0 +1,51 @@
+// eslint-disable-next-line no-use-before-define
+import React, { useEffect, useState } from 'react'
+import Draggable from 'react-draggable'
+import './dragbar.css'
+
+interface IRemixDragBarUi {
+ refObject: React.MutableRefObject;
+ setHideStatus: (hide: boolean) => void;
+ hidden: boolean
+ minHeight?: number
+}
+
+const DragBar = (props: IRemixDragBarUi) => {
+ const [dragState, setDragState] = useState(false)
+ const [dragBarPosY, setDragBarPosY] = useState(0)
+ const nodeRef = React.useRef(null) // fix for strictmode
+
+ function stopDrag (e: MouseEvent, data: any) {
+ const h = window.innerHeight - data.y
+ props.refObject.current.setAttribute('style', `height: ${h}px;`)
+ setDragBarPosY(window.innerHeight - props.refObject.current.offsetHeight)
+ setDragState(false)
+ }
+ const handleResize = () => {
+ setDragBarPosY(window.innerHeight - props.refObject.current.offsetHeight)
+ }
+
+ useEffect(() => {
+ handleResize()
+ }, [props.hidden])
+
+ useEffect(() => {
+ window.addEventListener('resize', handleResize)
+ // TODO: not a good way to wait on the ref doms element to be rendered of course
+ setTimeout(() =>
+ handleResize(), 2000)
+ return () => window.removeEventListener('resize', handleResize)
+ }, [])
+
+ function startDrag () {
+ setDragState(true)
+ }
+ return <>
+
+
+
+
+ >
+}
+
+export default DragBar
diff --git a/libs/remix-ui/panel/src/lib/main/main-panel.css b/libs/remix-ui/panel/src/lib/main/main-panel.css
new file mode 100644
index 00000000000..d569338fab1
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/main/main-panel.css
@@ -0,0 +1,8 @@
+.mainview {
+ display : flex;
+ flex-direction : column;
+ height : 100%;
+ width : 100%;
+ position: relative;
+ }
+
diff --git a/libs/remix-ui/panel/src/lib/main/main-panel.tsx b/libs/remix-ui/panel/src/lib/main/main-panel.tsx
new file mode 100644
index 00000000000..4fb00ddf65c
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/main/main-panel.tsx
@@ -0,0 +1,60 @@
+/* eslint-disable no-unused-expressions */
+import { AppContext } from 'libs/remix-ui/app/src/lib/remix-app/context/context'
+import React, { useContext, useEffect, useLayoutEffect, useRef, useState } from 'react' // eslint-disable-line
+import DragBar from '../dragbar/dragbar'
+import RemixUIPanelPlugin from '../plugins/panel-plugin'
+import { PluginRecord } from '../types'
+import './main-panel.css'
+
+const RemixUIMainPanel = () => {
+ const appContext = useContext(AppContext)
+ const [plugins, setPlugins] = useState([])
+ const editorRef = useRef(null)
+ const mainPanelRef = useRef(null)
+ const tabsRef = useRef(null)
+ const terminalRef = useRef(null)
+
+ const refs = [tabsRef, editorRef, mainPanelRef, terminalRef]
+
+ const renderPanels = () => {
+ if (appContext) {
+ const pluginPanels: PluginRecord[] = []
+ Object.values(appContext.layout.panels).map((panel: any) => {
+ pluginPanels.push({
+ profile: panel.plugin.profile,
+ active: panel.active,
+ view: panel.plugin.profile.name === 'tabs' ? panel.plugin.renderTabsbar() : panel.plugin.render(),
+ class: panel.plugin.profile.name + '-wrap ' + (panel.minimized ? 'minimized' : ''),
+ minimized: panel.minimized
+ })
+ })
+ setPlugins(pluginPanels)
+ }
+ }
+
+ useEffect(() => {
+ renderPanels()
+ appContext.layout.event.on('change', () => {
+ renderPanels()
+ })
+ }, [])
+
+ return (
+
+ {Object.values(plugins).map((pluginRecord, i) => {
+ return (
+
+ {(pluginRecord.profile.name === 'terminal') ? {}} refObject={terminalRef}> : null}
+
+
+ )
+ })}
+
+ )
+}
+
+export default RemixUIMainPanel
diff --git a/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
new file mode 100644
index 00000000000..5acd50541a3
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable jsx-a11y/anchor-has-content */
+import React, { useEffect, useRef, useState } from 'react' // eslint-disable-line
+import { PluginRecord } from '../types'
+import './panel.css'
+
+export interface RemixPanelProps {
+ plugins: Record;
+ }
+const RemixUIPanelHeader = (props: RemixPanelProps) => {
+ const [plugin, setPlugin] = useState()
+
+ useEffect(() => {
+ if (props.plugins) {
+ const p = Object.values(props.plugins).find((pluginRecord) => {
+ return pluginRecord.active === true
+ })
+ setPlugin(p)
+ }
+ }, [props])
+
+ return (
+ {plugin?.profile.displayName || plugin?.profile.name}
+ {plugin?.profile.documentation ? () : ''}
+ )
+}
+
+export default RemixUIPanelHeader
diff --git a/libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx b/libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx
new file mode 100644
index 00000000000..9eb30391bc6
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx
@@ -0,0 +1,37 @@
+/* eslint-disable no-undef */
+import React, { forwardRef, useEffect, useRef, useState } from 'react' // eslint-disable-line
+import { PluginRecord } from '../types'
+import './panel.css'
+interface panelPLuginProps {
+ pluginRecord: PluginRecord
+}
+
+const RemixUIPanelPlugin = (props: panelPLuginProps, panelRef: any) => {
+ const localRef = useRef(null)
+ const [view, setView] = useState()
+ useEffect(() => {
+ const ref:any = panelRef || localRef
+ if (ref.current) {
+ if (props.pluginRecord.view) {
+ if (React.isValidElement(props.pluginRecord.view)) {
+ setView(props.pluginRecord.view)
+ } else {
+ ref.current.appendChild(props.pluginRecord.view)
+ }
+ }
+ }
+ }, [])
+
+ return (
+
+ {view}
+
+ )
+}
+
+export default forwardRef(RemixUIPanelPlugin)
diff --git a/libs/remix-ui/panel/src/lib/plugins/panel.css b/libs/remix-ui/panel/src/lib/plugins/panel.css
new file mode 100644
index 00000000000..d2b2133667e
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/plugins/panel.css
@@ -0,0 +1,110 @@
+.panel {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ flex: auto;
+}
+
+.swapitTitle {
+ margin: 0;
+ text-transform: uppercase;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.swapitTitle i {
+ padding-left: 6px;
+ font-size: 14px;
+}
+
+.swapitHeader {
+ display: flex;
+ align-items: center;
+ padding: 16px 24px 15px;
+ justify-content: space-between;
+ text-transform: uppercase;
+}
+
+.icons i {
+ height: 80%;
+ cursor: pointer;
+}
+
+.pluginsContainer {
+ height: 100%;
+ overflow-y: auto;
+}
+
+.titleInfo {
+ padding-left: 10px;
+}
+
+.versionBadge {
+ background-color: var(--light);
+ padding: 0 7px;
+ font-weight: bolder;
+ margin-left: 5px;
+ text-transform: lowercase;
+ cursor: default;
+}
+
+iframe {
+ height: 100%;
+ width: 100%;
+ border: 0;
+}
+
+.plugins {
+ height: 100%;
+}
+
+.plugItIn {
+ display: none;
+ height: 100%;
+}
+
+.plugItIn>div {
+ overflow-y: auto;
+ overflow-x: hidden;
+ height: 100%;
+ width: 100%;
+}
+
+.plugItIn.active {
+ display: block;
+}
+
+.pluginsContainer {
+ height: 100%;
+ overflow-y: hidden;
+}
+
+#editorView {
+ height: 100%;
+ width: 100%;
+ border: 0;
+ display: block;
+}
+
+#mainPanel {
+ height: 100%;
+ width: 100%;
+ border: 0;
+ display: block;
+}
+
+.mainPanel-wrap, .editor-wrap {
+ flex: 1;
+ min-height: 100px;
+}
+
+.terminal-wrap {
+ min-height: 35px;
+ height: 20%;
+}
+
+.terminal-wrap.minimized {
+ height: 2rem !important;
+}
diff --git a/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx
new file mode 100644
index 00000000000..37fa018c92a
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx
@@ -0,0 +1,29 @@
+/* eslint-disable no-undef */
+import React, { useEffect, useState } from 'react' // eslint-disable-line
+import './panel.css'
+import RemixUIPanelPlugin from './panel-plugin'
+import { PluginRecord } from '../types'
+
+/* eslint-disable-next-line */
+export interface RemixPanelProps {
+ plugins: Record
+ header: JSX.Element
+}
+
+export function RemixPluginPanel (props: RemixPanelProps) {
+ return (
+ <>
+ {props.header}
+
+
+ {Object.values(props.plugins).map((pluginRecord) => {
+ return
+ })}
+
+
+ >
+
+ )
+}
+
+export default RemixPluginPanel
diff --git a/libs/remix-ui/panel/src/lib/types/index.ts b/libs/remix-ui/panel/src/lib/types/index.ts
new file mode 100644
index 00000000000..f8407033ab4
--- /dev/null
+++ b/libs/remix-ui/panel/src/lib/types/index.ts
@@ -0,0 +1,9 @@
+import { Profile } from '@remixproject/plugin-utils'
+
+export type PluginRecord = {
+ profile: Profile
+ view: any
+ active: boolean
+ class?: string
+ minimized?: boolean
+ }
diff --git a/libs/remix-ui/panel/tsconfig.json b/libs/remix-ui/panel/tsconfig.json
new file mode 100644
index 00000000000..8bd701c578c
--- /dev/null
+++ b/libs/remix-ui/panel/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "allowJs": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.lib.json"
+ }
+ ]
+}
diff --git a/libs/remix-ui/panel/tsconfig.lib.json b/libs/remix-ui/panel/tsconfig.lib.json
new file mode 100644
index 00000000000..b560bc4dec6
--- /dev/null
+++ b/libs/remix-ui/panel/tsconfig.lib.json
@@ -0,0 +1,13 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "types": ["node"]
+ },
+ "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"]
+}
diff --git a/libs/remix-ui/plugin-manager/src/types.d.ts b/libs/remix-ui/plugin-manager/src/types.d.ts
index d30ae314570..66ee57bc77e 100644
--- a/libs/remix-ui/plugin-manager/src/types.d.ts
+++ b/libs/remix-ui/plugin-manager/src/types.d.ts
@@ -4,6 +4,7 @@ import { EventEmitter } from 'events'
import { Engine } from '@remixproject/engine/lib/engine'
import { PluginBase, Profile } from '@remixproject/plugin-utils'
import { IframePlugin, ViewPlugin, WebsocketPlugin } from '@remixproject/engine-web'
+import { IframeReactPlugin } from '@remix-ui/app'
/* eslint-disable camelcase */
interface SetPluginOptionType {
@@ -88,7 +89,7 @@ export class PluginManagerComponent extends ViewPlugin extends Plugin implements
render(): HTMLDivElement
getAndFilterPlugins: (filter?: string, profiles?: Profile[]) => void
triggerEngineEventListener: () => void
- activateAndRegisterLocalPlugin: (localPlugin: IframePlugin | WebsocketPlugin) => Promise
+ activateAndRegisterLocalPlugin: (localPlugin: IframePlugin | IframeReactPlugin | WebsocketPlugin) => Promise
activeProfiles: string[]
_paq: any
}
diff --git a/libs/remix-ui/solidity-unit-testing/.babelrc b/libs/remix-ui/solidity-unit-testing/.babelrc
index 09d67939cc9..64a37486919 100644
--- a/libs/remix-ui/solidity-unit-testing/.babelrc
+++ b/libs/remix-ui/solidity-unit-testing/.babelrc
@@ -1,4 +1,4 @@
{
"presets": ["@nrwl/react/babel"],
"plugins": []
-}
+}
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts b/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts
index dafe6f78cf1..d0efd289b58 100644
--- a/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts
+++ b/libs/remix-ui/terminal/src/lib/actions/terminalAction.ts
@@ -106,8 +106,8 @@ export const registerErrorScriptRunnerAction = (on, commandName, commandFn, disp
})
}
-export const listenOnNetworkAction = async (event, isListening) => {
- event.trigger('listenOnNetWork', [isListening])
+export const listenOnNetworkAction = async (plugins, isListening) => {
+ plugins.txListener.setListenOnNetwork(isListening)
}
export const initListeningOnNetwork = (plugins, dispatch: React.Dispatch) => {
diff --git a/libs/remix-ui/terminal/src/lib/custom-hooks/useDragTerminal.tsx b/libs/remix-ui/terminal/src/lib/custom-hooks/useDragTerminal.tsx
deleted file mode 100644
index aba4bbf6a56..00000000000
--- a/libs/remix-ui/terminal/src/lib/custom-hooks/useDragTerminal.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import React, { useEffect, useState } from 'react'
-
-export const useDragTerminal = (minHeight: number, defaultPosition: number) => {
- const [isOpen, setIsOpen] = useState(defaultPosition > minHeight)
- const [lastYPosition, setLastYPosition] = useState(0)
- const [terminalPosition, setTerminalPosition] = useState(defaultPosition)
- // Used to save position of the terminal when it is closed
- const [lastTerminalPosition, setLastTerminalPosition] = useState(defaultPosition)
- const [isDragging, setIsDragging] = useState(false)
-
- const handleDraggingStart = (event: React.MouseEvent) => {
- setLastYPosition(event.clientY)
- setIsDragging(true)
- }
-
- const handleDragging = (event: MouseEvent) => {
- event.preventDefault()
-
- if (isDragging) {
- const mouseYPosition = event.clientY
- const difference = lastYPosition - mouseYPosition
- const newTerminalPosition = terminalPosition + difference
- setTerminalPosition(newTerminalPosition)
- setLastYPosition(mouseYPosition)
- }
- }
-
- const handleDraggingEnd = () => {
- if (!isDragging) return
-
- setIsDragging(false)
-
- // Check terminal position to determine if it should be open or closed
- setIsOpen(terminalPosition > minHeight)
- }
-
- const handleToggleTerminal = (event: React.MouseEvent) => {
- event.preventDefault()
- event.stopPropagation()
-
- if (isOpen) {
- setLastTerminalPosition(terminalPosition)
- setLastYPosition(0)
- setTerminalPosition(minHeight)
- } else {
- setTerminalPosition(lastTerminalPosition <= minHeight ? 323 : lastTerminalPosition)
- }
-
- setIsOpen(!isOpen)
- }
-
- // Add event listeners for dragging
- useEffect(() => {
- document.addEventListener('mousemove', handleDragging)
- document.addEventListener('mouseup', handleDraggingEnd)
-
- return () => {
- document.removeEventListener('mousemove', handleDragging)
- document.removeEventListener('mouseup', handleDraggingEnd)
- }
- }, [handleDragging, handleDraggingEnd])
-
- // Reset terminal position
- useEffect(() => {
- if (!terminalPosition) {
- setTerminalPosition(defaultPosition)
- }
- }, [terminalPosition, setTerminalPosition])
-
- return {
- isOpen,
- terminalPosition,
- isDragging,
- handleDraggingStart,
- handleToggleTerminal
- }
-}
diff --git a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
index 46dbea432d4..3536750efcc 100644
--- a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
+++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState, useEffect, useReducer, useRef, SyntheticEvent, MouseEvent } from 'react' // eslint-disable-line
import { registerCommandAction, registerLogScriptRunnerAction, registerInfoScriptRunnerAction, registerErrorScriptRunnerAction, registerWarnScriptRunnerAction, listenOnNetworkAction, initListeningOnNetwork } from './actions/terminalAction'
import { initialState, registerCommandReducer, addCommandHistoryReducer, registerScriptRunnerReducer } from './reducers/terminalReducer'
@@ -17,7 +18,6 @@ import RenderKnownTransactions from './components/RenderKnownTransactions' // es
import parse from 'html-react-parser'
import { EMPTY_BLOCK, KNOWN_TRANSACTION, RemixUiTerminalProps, UNKNOWN_TRANSACTION } from './types/terminalTypes'
import { wrapScript } from './utils/wrapScript'
-import { useDragTerminal } from './custom-hooks/useDragTerminal'
/* eslint-disable-next-line */
export interface ClipboardEvent extends SyntheticEvent {
@@ -28,7 +28,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const { call, _deps, on, config, event, version } = props.plugin
const [_cmdIndex, setCmdIndex] = useState(-1)
const [_cmdTemp, setCmdTemp] = useState('')
-
+ const [isOpen, setIsOpen] = useState(true)
const [newstate, dispatch] = useReducer(registerCommandReducer, initialState)
const [cmdHistory, cmdHistoryDispatch] = useReducer(addCommandHistoryReducer, initialState)
const [, scriptRunnerDispatch] = useReducer(registerScriptRunnerReducer, initialState)
@@ -79,24 +79,6 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const terminalMenuOffsetHeight = (terminalMenu.current && terminalMenu.current.offsetHeight) || 35
const terminalDefaultPosition = config.get('terminal-top-offset')
- const {
- isOpen,
- isDragging,
- terminalPosition,
- handleDraggingStart,
- handleToggleTerminal
- } = useDragTerminal(terminalMenuOffsetHeight, terminalDefaultPosition)
-
- // Check open state
- useEffect(() => {
- const resizeValue = isOpen ? [config.get('terminal-top-offset')] : []
- event.trigger('resize', resizeValue)
- }, [isOpen])
-
- useEffect(() => {
- event.trigger('resize', [terminalPosition])
- }, [terminalPosition])
-
const scrollToBottom = () => {
messagesEndRef.current.scrollIntoView({ behavior: 'smooth' })
}
@@ -106,6 +88,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
logHtml: (html) => {
scriptRunnerDispatch({ type: 'html', payload: { message: [html.innerText] } })
},
+
log: (message) => {
scriptRunnerDispatch({ type: 'log', payload: { message: [message] } })
}
@@ -332,8 +315,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const listenOnNetwork = (e: any) => {
const isListening = e.target.checked
- // setIsListeningOnNetwork(isListening)
- listenOnNetworkAction(event, isListening)
+ listenOnNetworkAction(props.plugin, isListening)
}
const onChange = (event: any) => {
@@ -426,10 +408,14 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
setAutoCompleteState(prevState => ({ ...prevState, activeSuggestion: 0, showSuggestions: false }))
}
+ const handleToggleTerminal = () => {
+ setIsOpen(!isOpen)
+ props.plugin.call('layout', 'minimize', props.plugin.profile.name, isOpen)
+ }
+
return (
-
+
-
diff --git a/nx.json b/nx.json
index e1bc0d858ac..f2aa0098999 100644
--- a/nx.json
+++ b/nx.json
@@ -145,6 +145,9 @@
"remix-ui-tabs": {
"tags": []
},
+ "remix-ui-panel": {
+ "tags": []
+ },
"remix-ui-theme-module": {
"tags": []
},
diff --git a/package.json b/package.json
index 03e89015e97..0a838a7a407 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,7 @@
"workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph",
"help": "nx help",
- "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-helper,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,solidity-unit-testing,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs",
+ "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-helper,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin,remix-ui-renderer,remix-ui-publish-to-storage,remix-ui-solidity-compiler,solidity-unit-testing,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs,remix-ui-panel",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"publish:libs": "npm run build:libs && lerna publish --skip-git && npm run bumpVersion:libs",
@@ -162,7 +162,7 @@
"chokidar": "^2.1.8",
"color-support": "^1.1.3",
"commander": "^2.20.3",
- "core-js": "^3.19.3",
+ "core-js": "^3.6.5",
"deep-equal": "^1.0.1",
"document-register-element": "1.13.1",
"ethereumjs-util": "^7.0.10",
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 4ef2c10dcb2..21dfeb4ee8e 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -69,8 +69,11 @@
"@remix-ui/tabs": ["libs/remix-ui/tabs/src/index.ts"],
"@remix-ui/helper": ["libs/remix-ui/helper/src/index.ts"],
"@remix-ui/app": ["libs/remix-ui/app/src/index.ts"],
- "@remix-ui/vertical-icons-panel": ["libs/remix-ui/vertical-icons-panel/src/index.ts"],
+ "@remix-ui/vertical-icons-panel": [
+ "libs/remix-ui/vertical-icons-panel/src/index.ts"
+ ],
"@remix-ui/theme-module": ["libs/remix-ui/theme-module/src/index.ts"],
+ "@remix-ui/panel": ["libs/remix-ui/panel/src/index.ts"],
"@remix-ui/editor-context-view": ["libs/remix-ui/editor-context-view/src/index.ts"],
"@remix-ui/solidity-unit-testing": [
"libs/remix-ui/solidity-unit-testing/src/index.ts"
diff --git a/workspace.json b/workspace.json
index d4a9f6fcd40..76b236717f3 100644
--- a/workspace.json
+++ b/workspace.json
@@ -1107,6 +1107,21 @@
}
}
},
+ "remix-ui-panel": {
+ "root": "libs/remix-ui/panel",
+ "sourceRoot": "libs/remix-ui/panel/src",
+ "projectType": "library",
+ "architect": {
+ "lint": {
+ "builder": "@nrwl/linter:lint",
+ "options": {
+ "linter": "eslint",
+ "tsConfig": ["libs/remix-ui/panel/tsconfig.lib.json"],
+ "exclude": ["**/node_modules/**", "!libs/remix-ui/panel/**/*"]
+ }
+ }
+ }
+ },
"solidity-unit-testing": {
"root": "libs/remix-ui/solidity-unit-testing",
"sourceRoot": "libs/remix-ui/solidity-unit-testing/src",