pull/1857/head
bunsenstraat 3 years ago
commit 3b0f422635
  1. 1
      README.md
  2. 66
      apps/remix-ide-e2e/src/tests/importFromGithub.test.ts
  3. 369
      apps/remix-ide/src/app.js
  4. 3
      apps/remix-ide/src/app/editor/editor.js
  5. 20
      apps/remix-ide/src/app/tabs/theme-module.js
  6. 571
      apps/remix-ide/src/app/ui/landing-page/landing-page.js
  7. BIN
      apps/remix-ide/src/assets/img/solhintLogo.png
  8. BIN
      apps/remix-ide/src/assets/img/solhintLogo.webp
  9. 10
      apps/remix-ide/src/framingService.js
  10. 1
      apps/remix-ide/src/index.html
  11. 10
      apps/remix-ide/src/index.js
  12. 16
      apps/remix-ide/src/index.tsx
  13. 1
      apps/remix-ide/src/production.index.html
  14. 104
      apps/remix-ide/src/walkthroughService.js
  15. 1
      apps/remix-ide/src/webpack.index.html
  16. 3
      apps/remix-ide/tsconfig.json
  17. 4
      libs/remix-ui/app/.babelrc
  18. 248
      libs/remix-ui/app/.eslintrc
  19. 1
      libs/remix-ui/app/src/index.ts
  20. 5
      libs/remix-ui/app/src/lib/remix-app/context/context.tsx
  21. 26
      libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.css
  22. 53
      libs/remix-ui/app/src/lib/remix-app/dragbar/dragbar.tsx
  23. 43
      libs/remix-ui/app/src/lib/remix-app/modals/alert.tsx
  24. 51
      libs/remix-ui/app/src/lib/remix-app/modals/matomo.tsx
  25. 16
      libs/remix-ui/app/src/lib/remix-app/modals/splashscreen.tsx
  26. 90
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  27. 71
      libs/remix-ui/app/src/lib/remix-app/style/remix-app.css
  28. 19
      libs/remix-ui/app/tsconfig.json
  29. 13
      libs/remix-ui/app/tsconfig.lib.json
  30. 15
      libs/remix-ui/app/tsconfig.spec.json
  31. 133
      libs/remix-ui/editor/src/lib/cairoSyntax.ts
  32. 11
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  33. 3
      libs/remix-ui/helper/src/lib/remix-ui-helper.ts
  34. 4
      libs/remix-ui/home-tab/.babelrc
  35. 248
      libs/remix-ui/home-tab/.eslintrc
  36. 7
      libs/remix-ui/home-tab/README.md
  37. 1
      libs/remix-ui/home-tab/src/index.ts
  38. 27
      libs/remix-ui/home-tab/src/lib/components/pluginButton.tsx
  39. 82
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.css
  40. 370
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
  41. 16
      libs/remix-ui/home-tab/src/lib/themeContext.tsx
  42. 16
      libs/remix-ui/home-tab/tsconfig.json
  43. 13
      libs/remix-ui/home-tab/tsconfig.lib.json
  44. 4
      libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx
  45. 2
      libs/remix-ui/modal-dialog/src/lib/types/index.ts
  46. 1
      libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx
  47. 34
      libs/remix-ui/settings/src/lib/remix-ui-settings.tsx
  48. 77
      libs/remix-ui/terminal/src/lib/custom-hooks/useDragTerminal.tsx
  49. 9
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.css
  50. 96
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
  51. 12
      libs/remix-ui/theme-module/.babelrc
  52. 18
      libs/remix-ui/theme-module/.eslintrc.json
  53. 7
      libs/remix-ui/theme-module/README.md
  54. 1
      libs/remix-ui/theme-module/src/index.ts
  55. 0
      libs/remix-ui/theme-module/src/lib/remix-ui-theme-module.module.css
  56. 106
      libs/remix-ui/theme-module/src/lib/remix-ui-theme-module.tsx
  57. 0
      libs/remix-ui/theme-module/src/reducers/themeModuleReducers.ts
  58. 20
      libs/remix-ui/theme-module/tsconfig.json
  59. 13
      libs/remix-ui/theme-module/tsconfig.lib.json
  60. 47
      libs/remix-ui/theme-module/types/theme-module.d.ts
  61. 1
      libs/remix-ui/toaster/src/lib/toaster.tsx
  62. 9
      nx.json
  63. 4589
      package-lock.json
  64. 8
      package.json
  65. 8
      tsconfig.base.json
  66. 10
      tsconfig.json
  67. 357
      workspace.json

@ -51,6 +51,7 @@ git clone https://github.com/ethereum/remix-project.git
```bash
cd remix-project
npm install
npm run build:libs // Build remix libs
nx build
nx serve
```

@ -0,0 +1,66 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
const testData = {
validURL: 'https://github.com/OpenZeppelin/openzeppelin-solidity/blob/67bca857eedf99bf44a4b6a0fc5b5ed553135316/contracts/access/Roles.sol',
invalidURL: 'https://github.com/Oppelin/Roles.sol'
}
module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'Import from GitHub Modal': function (browser: NightwatchBrowser) {
browser.clickLaunchIcon('home')
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('filePanel')
.click('div[title="home"]')
.waitForElementVisible('button[data-id="landingPageImportFromGitHubButton"]')
.pause(1000)
.scrollAndClick('button[data-id="landingPageImportFromGitHubButton"]')
.waitForElementVisible('*[data-id="homeTabModalDialogModalTitle-react"]')
.assert.containsText('*[data-id="homeTabModalDialogModalTitle-react"]', 'Import from Github')
.waitForElementVisible('*[data-id="homeTabModalDialogModalBody-react"]')
.assert.containsText('*[data-id="homeTabModalDialogModalBody-react"]', 'Enter the github URL you would like to load.')
.waitForElementVisible('*[data-id="homeTabModalDialogCustomPromptText"]')
.refresh()
},
'Display Error Message For Invalid GitHub URL Modal': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('settings')
.clickLaunchIcon('filePanel')
.scrollAndClick('*[data-id="landingPageImportFromGitHubButton"]')
.waitForElementVisible('input[data-id="homeTabModalDialogCustomPromptText"]')
.execute(() => {
(document.querySelector('input[data-id="homeTabModalDialogCustomPromptText"]') as any).focus()
}, [], () => {})
.setValue('input[data-id="homeTabModalDialogCustomPromptText"]', testData.invalidURL)
.waitForElementVisible('*[data-id="homeTab-modal-footer-ok-react"]')
.scrollAndClick('[data-id="homeTab-modal-footer-ok-react"]') // submitted
.waitForElementVisible('*[data-shared="tooltipPopup"]')
.assert.containsText('*[data-shared="tooltipPopup"] span', 'not found ' + testData.invalidURL)
},
'Import From Github For Valid URL': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('settings')
.clickLaunchIcon('filePanel')
.scrollAndClick('*[data-id="landingPageImportFromGitHubButton"]')
.waitForElementVisible('*[data-id="homeTabModalDialogCustomPromptText"]')
.clearValue('*[data-id="homeTabModalDialogCustomPromptText"]')
.execute(() => {
(document.querySelector('input[data-id="homeTabModalDialogCustomPromptText"]') as any).focus()
}, [], () => {})
.setValue('input[data-id="homeTabModalDialogCustomPromptText"]', testData.validURL)
.waitForElementVisible('*[data-id="homeTab-modal-footer-ok-react"]')
.scrollAndClick('[data-id="homeTab-modal-footer-ok-react"]')
.openFile('github/OpenZeppelin/openzeppelin-solidity/contracts/access/Roles.sol')
.waitForElementVisible("div[title='default_workspace/github/OpenZeppelin/openzeppelin-solidity/contracts/access/Roles.sol'")
.end()
}
}

@ -1,13 +1,7 @@
'use strict'
import { basicLogo } from './app/ui/svgLogo'
import { RunTab, makeUdapp } from './app/udapp'
import PanelsResize from './lib/panels-resize'
import { RemixEngine } from './remixEngine'
import { RemixAppManager } from './remixAppManager'
import { FramingService } from './framingService'
import { WalkthroughService } from './walkthroughService'
import { MainView } from './app/panels/main-view'
import { ThemeModule } from './app/tabs/theme-module'
import { NetworkModule } from './app/tabs/network-module'
@ -17,14 +11,16 @@ 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'
import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports } from '@remix-project/core-plugin'
import migrateFileSystem from './migrateFileSystem'
const isElectron = require('is-electron')
const csjs = require('csjs-inject')
const yo = require('yo-yo')
const remixLib = require('@remix-project/remix-lib')
const registry = require('./global/registry')
@ -33,8 +29,7 @@ const Storage = remixLib.Storage
const RemixDProvider = require('./app/files/remixDProvider')
const HardhatProvider = require('./app/tabs/hardhat-provider')
const Config = require('./config')
const modalDialogCustom = require('./app/ui/modal-dialog-custom')
const modalDialog = require('./app/ui/modaldialog')
const FileManager = require('./app/files/fileManager')
const FileProvider = require('./app/files/fileProvider')
const DGitProvider = require('./app/files/dgitProvider')
@ -54,93 +49,13 @@ const FilePanel = require('./app/panels/file-panel')
const Editor = require('./app/editor/editor')
const Terminal = require('./app/panels/terminal')
const ContextualListener = require('./app/editor/contextualListener')
const _paq = window._paq = window._paq || []
const css = csjs`
html { box-sizing: border-box; }
*, *:before, *:after { box-sizing: inherit; }
body {
/* font: 14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; */
font-size : .8rem;
}
pre {
overflow-x: auto;
}
.remixIDE {
width : 100vw;
height : 100vh;
overflow : hidden;
flex-direction : row;
display : flex;
}
.mainpanel {
display : flex;
flex-direction : column;
overflow : hidden;
flex : 1;
}
.iconpanel {
display : flex;
flex-direction : column;
overflow : hidden;
width : 50px;
user-select : none;
}
.sidepanel {
display : flex;
flex-direction : row-reverse;
width : 320px;
overflow : auto;
}
.highlightcode {
position : absolute;
z-index : 20;
background-color : var(--info);
}
.highlightcode_fullLine {
position : absolute;
z-index : 20;
background-color : var(--info);
opacity : 0.5;
}
.centered {
position : fixed;
top : 20%;
left : 45%;
width : 200px;
height : 200px;
}
.centered svg path {
fill: var(--secondary);
}
.centered svg polygon {
fill : var(--secondary);
}
.onboarding {
color : var(--text-info);
background-color : var(--info);
}
.matomoBtn {
width : 100px;
}
`
class App {
class AppComponent {
constructor (api = {}, events = {}, opts = {}) {
var self = this
const self = this
self.appManager = new RemixAppManager({})
self._components = {}
self._view = {}
self._view.splashScreen = yo`
<div class=${css.centered}>
${basicLogo()}
<div class="info-secondary" style="text-align:center">
REMIX IDE
</div>
</div>
`
document.body.appendChild(self._view.splashScreen)
self.registry = registry
// setup storage
const configStorage = new Storage('config-v0.8:')
@ -162,67 +77,22 @@ class App {
migrateFileSystem(self._components.filesProviders.browser)
}
init () {
this.run().catch(console.error)
}
render () {
var self = this
if (self._view.el) return self._view.el
// not resizable
self._view.iconpanel = yo`
<div id="icon-panel" data-id="remixIdeIconPanel" class="${css.iconpanel} bg-light">
${''}
</div>
`
// center panel, resizable
self._view.sidepanel = yo`
<div id="side-panel" data-id="remixIdeSidePanel" style="min-width: 320px;" class="${css.sidepanel} border-right border-left">
${''}
</div>
`
// handle the editor + terminal
self._view.mainpanel = yo`
<div id="main-panel" data-id="remixIdeMainPanel" class=${css.mainpanel}>
${''}
</div>
`
self._components.resizeFeature = new PanelsResize(self._view.sidepanel)
self._view.el = yo`
<div style="visibility:hidden" class=${css.remixIDE} data-id="remixIDE">
${self._view.iconpanel}
${self._view.sidepanel}
${self._components.resizeFeature.render()}
${self._view.mainpanel}
</div>
`
return self._view.el
}
async run () {
var self = this
// check the origin and warn message
if (window.location.hostname === 'yann300.github.io') {
modalDialogCustom.alert('This UNSTABLE ALPHA branch of Remix has been moved to http://ethereum.github.io/remix-live-alpha.')
} else if (window.location.hostname === 'remix-alpha.ethereum.org' ||
(window.location.hostname === 'ethereum.github.io' && window.location.pathname.indexOf('/remix-live-alpha') === 0)) {
modalDialogCustom.alert('Welcome to the Remix alpha instance. Please use it to try out latest features. But use preferably https://remix.ethereum.org for any production work.')
} else if (window.location.protocol.indexOf('http') === 0 &&
window.location.hostname !== 'remix.ethereum.org' &&
window.location.hostname !== 'localhost' &&
window.location.hostname !== '127.0.0.1') {
modalDialogCustom.alert(`The Remix IDE has moved to http://remix.ethereum.org.\n
This instance of Remix you are visiting WILL NOT BE UPDATED.\n
Please make a backup of your contracts and start using http://remix.ethereum.org`)
}
if (window.location.protocol.indexOf('https') === 0) {
toolTip('You are using an `https` connection. Please switch to `http` if you are using Remix against an `http Web3 provider` or allow Mixed Content in your browser.')
const self = this
// APP_MANAGER
const appManager = self.appManager
const pluginLoader = self.appManager.pluginLoader
self.workspace = pluginLoader.get()
self.engine = new RemixEngine()
self.engine.register(appManager)
const matomoDomains = {
'remix-alpha.ethereum.org': 27,
'remix-beta.ethereum.org': 25,
'remix.ethereum.org': 23
}
self.showMatamo = (matomoDomains[window.location.hostname] && !registry.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
@ -233,23 +103,11 @@ class App {
}
}
// APP_MANAGER
const appManager = self.appManager
const pluginLoader = appManager.pluginLoader
const workspace = pluginLoader.get()
const engine = new RemixEngine()
engine.register(appManager)
// SERVICES
// ----------------- theme service ---------------------------------
const themeModule = new ThemeModule(registry)
registry.put({ api: themeModule, name: 'themeModule' })
themeModule.initTheme(() => {
setTimeout(() => {
document.body.removeChild(self._view.splashScreen)
self._view.el.style.visibility = 'visible'
}, 1500)
})
self.themeModule = new ThemeModule(registry)
registry.put({ api: self.themeModule, name: 'themeModule' })
// ----------------- editor service ----------------------------
const editor = new Editor() // wrapper around ace editor
registry.put({ api: editor, name: 'editor' })
@ -289,10 +147,10 @@ class App {
{ appManager, blockchain },
{
getPosition: (event) => {
var limitUp = 36
var limitDown = 20
var height = window.innerHeight
var newpos = (event.pageY < limitUp) ? limitUp : event.pageY
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
return height - newpos
}
@ -300,10 +158,10 @@ class App {
)
const contextualListener = new ContextualListener({ editor })
engine.register([
self.engine.register([
blockchain,
contentImport,
themeModule,
self.themeModule,
editor,
fileManager,
compilerMetadataGenerator,
@ -315,110 +173,44 @@ class App {
web3Provider,
fetchAndCompile,
dGitProvider,
hardhatProvider
hardhatProvider,
self.walkthroughService
])
// LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel(registry.get('config').api)
const mainview = new MainView(contextualListener, editor, appPanel, fileManager, appManager, terminal)
registry.put({ api: mainview, name: 'mainview' })
const appPanel = new MainPanel()
self.mainview = new MainView(contextualListener, editor, appPanel, fileManager, appManager, terminal)
registry.put({ api: self.mainview, name: 'mainview' })
engine.register([
self.engine.register([
appPanel,
mainview.tabProxy
self.mainview.tabProxy
])
// those views depend on app_manager
const menuicons = new VerticalIcons(appManager)
const sidePanel = new SidePanel(appManager, menuicons)
const hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent(appManager, engine)
self.menuicons = new VerticalIcons(appManager)
self.sidePanel = new SidePanel(appManager, self.menuicons)
self.hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent(appManager, self.engine)
const filePanel = new FilePanel(appManager)
const landingPage = new LandingPage(appManager, menuicons, fileManager, filePanel, contentImport)
const settings = new SettingsTab(
const landingPage = new LandingPage(appManager, self.menuicons, fileManager, filePanel, contentImport)
self.settings = new SettingsTab(
registry.get('config').api,
editor,
appManager
)
// adding Views to the DOM
self._view.mainpanel.appendChild(mainview.render())
self._view.iconpanel.appendChild(menuicons.render())
self._view.sidepanel.appendChild(sidePanel.render())
document.body.appendChild(hiddenPanel.render()) // Hidden Panel is display none, it can be directly on body
engine.register([
menuicons,
self.engine.register([
self.menuicons,
landingPage,
hiddenPanel,
sidePanel,
self.hiddenPanel,
self.sidePanel,
filePanel,
pluginManagerComponent,
settings
self.settings
])
const queryParams = new QueryParams()
const params = queryParams.get()
const onAcceptMatomo = () => {
_paq.push(['forgetUserOptOut'])
// @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
settings.updateMatomoAnalyticsChoice(true)
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
startWalkthroughService()
}
const onDeclineMatomo = () => {
settings.updateMatomoAnalyticsChoice(false)
_paq.push(['optUserOut'])
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
startWalkthroughService()
}
const startWalkthroughService = () => {
const walkthroughService = new WalkthroughService(localStorage)
if (!params.code && !params.url && !params.minimizeterminal && !params.gist && !params.minimizesidepanel) {
walkthroughService.start()
}
}
// Ask to opt in to Matomo for remix, remix-alpha and remix-beta
const matomoDomains = {
'remix-alpha.ethereum.org': 27,
'remix-beta.ethereum.org': 25,
'remix.ethereum.org': 23
}
if (matomoDomains[window.location.hostname] && !registry.get('config').api.exists('settings/matomo-analytics')) {
modalDialog(
'Help us to improve Remix IDE',
yo`
<div>
<p>An Opt-in version of <a href="https://matomo.org" target="_blank">Matomo</a>, an open source data analytics platform is being used to improve Remix IDE.</p>
<p>We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.</p>
<p>All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: <a href="https://matomo.ethereum.org/index.php?module=MultiSites&action=index&idSite=23&period=day&date=yesterday" target="_blank">take a look</a>.</p>
<p>We do not collect nor store any personally identifiable information (PII).</p>
<p>For more info, see: <a href="https://medium.com/p/66ef69e14931/" target="_blank">Matomo Analyitcs on Remix iDE</a>.</p>
<p>You can change your choice in the Settings panel anytime.</p>
<div class="d-flex justify-content-around pt-3 border-top">
<button class="btn btn-primary ${css.matomoBtn}" onclick=${() => onAcceptMatomo()}>Sure</button>
<button class="btn btn-secondary ${css.matomoBtn}" onclick=${() => onDeclineMatomo()}>Decline</button>
</div>
</div>`,
{
label: '',
fn: null
},
{
label: '',
fn: null
}
)
} else {
startWalkthroughService()
}
// CONTENT VIEWS & DEFAULT PLUGINS
const compileTab = new CompileTab(registry.get('config').api, registry.get('filemanager').api)
const run = new RunTab(
@ -429,7 +221,7 @@ class App {
filePanel,
registry.get('compilersartefacts').api,
networkModule,
mainview,
self.mainview,
registry.get('fileproviders/browser').api
)
const analysis = new AnalysisTab(registry)
@ -443,7 +235,7 @@ class App {
contentImport
)
engine.register([
self.engine.register([
compileTab,
run,
debug,
@ -454,47 +246,55 @@ class App {
filePanel.hardhatHandle,
filePanel.slitherHandle
])
}
async activate () {
const queryParams = new QueryParams()
const params = queryParams.get()
const self = this
if (isElectron()) {
appManager.activatePlugin('remixd')
self.appManager.activatePlugin('remixd')
}
try {
engine.register(await appManager.registeredPlugins())
self.engine.register(await self.appManager.registeredPlugins())
} catch (e) {
console.log('couldn\'t register iframe plugins', e.message)
}
await appManager.activatePlugin(['editor'])
await appManager.activatePlugin(['theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
await appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
await appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await appManager.activatePlugin(['home'])
await appManager.activatePlugin(['settings'])
await appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport'])
appManager.on('filePanel', 'workspaceInitializationCompleted', async () => {
await appManager.registerContextMenuItems()
await self.appManager.activatePlugin(['editor'])
await self.appManager.activatePlugin(['theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
await self.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
await self.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await self.appManager.activatePlugin(['home'])
await self.appManager.activatePlugin(['settings'])
await self.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport'])
await self.appManager.activatePlugin(['settings'])
await self.appManager.activatePlugin(['walkthrough'])
self.appManager.on('filePanel', 'workspaceInitializationCompleted', async () => {
await self.appManager.registerContextMenuItems()
})
await appManager.activatePlugin(['filePanel'])
await self.appManager.activatePlugin(['filePanel'])
// Set workspace after initial activation
appManager.on('editor', 'editorMounted', () => {
if (Array.isArray(workspace)) {
appManager.activatePlugin(workspace).then(async () => {
self.appManager.on('editor', 'editorMounted', () => {
if (Array.isArray(self.workspace)) {
self.appManager.activatePlugin(self.workspace).then(async () => {
try {
if (params.deactivate) {
await appManager.deactivatePlugin(params.deactivate.split(','))
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
menuicons.select('solidity')
self.menuicons.select('solidity')
} else {
// If plugins are loaded from the URL params, we focus on the last one.
if (pluginLoader.current === 'queryParams' && workspace.length > 0) menuicons.select(workspace[workspace.length - 1])
if (self.appManager.pluginLoader.current === 'queryParams' && self.workspace.length > 0) self.menuicons.select(self.workspace[self.workspace.length - 1])
}
if (params.call) {
@ -502,21 +302,20 @@ class App {
if (callDetails.length > 1) {
toolTip(`initiating ${callDetails[0]} ...`)
// @todo(remove the timeout when activatePlugin is on 0.3.0)
appManager.call(...callDetails).catch(console.error)
self.appManager.call(...callDetails).catch(console.error)
}
}
}).catch(console.error)
}
})
// activate solidity plugin
appManager.activatePlugin(['solidity', 'udapp'])
self.appManager.activatePlugin(['solidity', 'udapp'])
// Load and start the service who manager layout and frame
const framingService = new FramingService(sidePanel, menuicons, mainview, this._components.resizeFeature)
const framingService = new FramingService(self.sidePanel, self.menuicons, self.mainview, null)
if (params.embed) framingService.embed()
framingService.start(params)
}
}
module.exports = App
export default AppComponent

@ -46,7 +46,8 @@ class Editor extends Plugin {
txt: 'text',
json: 'json',
abi: 'json',
rs: 'rust'
rs: 'rust',
cairo: 'cairo'
}
this.activated = false

@ -2,7 +2,6 @@ import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import QueryParams from '../../lib/query-params'
import * as packageJson from '../../../../../package.json'
import yo from 'yo-yo'
const _paq = window._paq = window._paq || []
const themes = [
@ -37,10 +36,12 @@ export class ThemeModule extends Plugin {
theme.url = window.location.origin + window.location.pathname + theme.url
return { ...acc, [theme.name]: theme }
}, {})
this._paq = _paq
let queryTheme = (new QueryParams()).get().theme
queryTheme = this.themes[queryTheme] ? queryTheme : null
let currentTheme = this._deps.config.get('settings/theme')
currentTheme = this.themes[currentTheme] ? currentTheme : null
this.currentThemeState = { queryTheme, currentTheme }
this.active = queryTheme || currentTheme || 'Dark'
this.forced = !!queryTheme
}
@ -58,11 +59,16 @@ export class ThemeModule extends Plugin {
/**
* Init the theme
*/
initTheme (callback) {
initTheme (callback) { // callback is setTimeOut in app.js which is always passed
if (callback) this.initCallback = callback
if (this.active) {
const nextTheme = this.themes[this.active] // Theme
document.documentElement.style.setProperty('--theme', nextTheme.quality)
const theme = yo`<link rel="stylesheet" href="${nextTheme.url}" id="theme-link"/>`
const theme = document.createElement('link')
theme.setAttribute('rel', 'stylesheet')
theme.setAttribute('href', nextTheme.url)
theme.setAttribute('id', 'theme-link')
theme.addEventListener('load', () => {
if (callback) callback()
})
@ -79,12 +85,16 @@ export class ThemeModule extends Plugin {
throw new Error(`Theme ${themeName} doesn't exist`)
}
const next = themeName || this.active // Name
if (next === this.active) return
if (next === this.active) return // --> exit out of this method
_paq.push(['trackEvent', 'themeModule', 'switchTo', next])
const nextTheme = this.themes[next] // Theme
if (!this.forced) this._deps.config.set('settings/theme', next)
document.getElementById('theme-link').remove()
const theme = yo`<link rel="stylesheet" href="${nextTheme.url}" id="theme-link"/>`
const theme = document.createElement('link')
theme.setAttribute('rel', 'stylesheet')
theme.setAttribute('href', nextTheme.url)
theme.setAttribute('id', 'theme-link')
theme.addEventListener('load', () => {
this.emit('themeLoaded', nextTheme)
this.events.emit('themeLoaded', nextTheme)

@ -1,110 +1,11 @@
/* global */
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import * as packageJson from '../../../../../../package.json'
import { ViewPlugin } from '@remixproject/engine-web'
import { migrateToWorkspace } from '../../../migrateFileSystem'
import JSZip from 'jszip'
import { RemixUiHomeTab } from '@remix-ui/home-tab' // eslint-disable-line
const yo = require('yo-yo')
const csjs = require('csjs-inject')
const globalRegistry = require('../../../global/registry')
const modalDialogCustom = require('../modal-dialog-custom')
const modalDialog = require('../modaldialog')
const tooltip = require('../tooltip')
const GistHandler = require('../../../lib/gist-handler')
const QueryParams = require('../../../lib/query-params.js')
const _paq = window._paq = window._paq || []
const css = csjs`
.text {
cursor: pointer;
font-weight: normal;
max-width: 300px;
user-select: none;
}
.text:hover {
cursor: pointer;
text-decoration: underline;
}
.homeContainer {
user-select: none;
overflow-y: hidden;
}
.mainContent {
overflow-y: auto;
flex-grow: 3;
}
.hpLogoContainer {
margin: 30px;
padding-right: 90px;
}
.mediaBadge {
font-size: 2em;
height: 2em;
width: 2em;
}
.mediaBadge:focus {
outline: none;
}
.image {
height: 1em;
width: 1em;
text-align: center;
}
.logoImg {
height: 10em;
}
.hpSections {
}
.rightPanel {
right: 0;
position: absolute;
z-index: 3;
}
.remixHomeMedia {
overflow-y: auto;
overflow-x: hidden;
max-height: 720px;
}
.panels {
box-shadow: 0px 0px 13px -7px;
}
.labelIt {
margin-bottom: 0;
}
.bigLabelSize {
font-size: 13px;
}
.seeAll {
margin-top: 7px;
white-space: nowrap;
}
.importFrom p {
margin-right: 10px;
}
.logoContainer img{
height: 150px;
opacity: 0.7;
}
.envLogo {
height: 16px;
}
.cursorStyle {
cursor: pointer;
}
.envButton {
width: 120px;
height: 70px;
}
.media {
overflow: hidden;
width: 400px;
transition: .5s ease-out;
z-index: 1000;
}
.migrationBtn {
width: 100px;
}
}
`
const profile = {
name: 'home',
@ -116,7 +17,6 @@ const profile = {
location: 'mainPanel',
version: packageJson.version
}
export class LandingPage extends ViewPlugin {
constructor (appManager, verticalIcons, fileManager, filePanel, contentImport) {
super(profile)
@ -127,459 +27,22 @@ export class LandingPage extends ViewPlugin {
this.appManager = appManager
this.verticalIcons = verticalIcons
this.gistHandler = new GistHandler()
const themeQuality = globalRegistry.get('themeModule').api.currentTheme().quality
window.addEventListener('resize', () => this.adjustMediaPanel())
window.addEventListener('click', (e) => this.hideMediaPanel(e))
this.twitterFrame = yo`
<div class="px-2 ${css.media}">
<a class="twitter-timeline"
data-width="350"
data-theme="${themeQuality}"
data-chrome="nofooter noheader transparent"
data-tweet-limit="8"
href="https://twitter.com/EthereumRemix"
>
</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
`
this.badgeTwitter = yo`<button
class="btn-info p-2 m-1 border rounded-circle ${css.mediaBadge} fab fa-twitter"
id="remixIDEHomeTwitterbtn"
onclick=${(e) => this.showMediaPanel(e)}
></button>`
this.badgeMedium = yo`<button
class="btn-danger p-2 m-1 border rounded-circle ${css.mediaBadge} fab fa-medium"
id="remixIDEHomeMediumbtn"
onclick=${(e) => this.showMediaPanel(e)}
></button>`
this.twitterPanel = yo`
<div id="remixIDE_TwitterBlock" class="p-2 mx-0 mb-0 d-none ${css.remixHomeMedia}">
${this.twitterFrame}
</div>
`
this.mediumPanel = yo`
<div id="remixIDE_MediumBlock" class="p-2 mx-0 mb-0 d-none ${css.remixHomeMedia}">
<div id="medium-widget" class="p-3 ${css.media}">
<div
id="retainable-rss-embed"
data-rss="https://medium.com/feed/remix-ide"
data-maxcols="1"
data-layout="grid"
data-poststyle="external"
data-readmore="More..."
data-buttonclass="btn mb-3"
data-offset="-100"
>
- </div>
</div>
</div>
`
this.adjustMediaPanel()
globalRegistry.get('themeModule').api.events.on('themeChanged', (theme) => {
this.onThemeChanged(theme.quality)
})
}
adjustMediaPanel () {
this.twitterPanel.style.maxHeight = Math.max(window.innerHeight - 150, 200) + 'px'
this.mediumPanel.style.maxHeight = Math.max(window.innerHeight - 150, 200) + 'px'
}
hideMediaPanel (e) {
const mediaPanelsTitle = document.getElementById('remixIDEMediaPanelsTitle')
const mediaPanels = document.getElementById('remixIDEMediaPanels')
if (!mediaPanelsTitle || !mediaPanels) return
if (!mediaPanelsTitle.contains(e.target) && !mediaPanels.contains(e.target)) {
this.mediumPanel.classList.remove('d-block')
this.mediumPanel.classList.add('d-none')
this.twitterPanel.classList.remove('d-block')
this.twitterPanel.classList.add('d-none')
}
}
onThemeChanged (themeQuality) {
const twitterFrame = yo`
<div class="px-2 ${css.media}">
<a class="twitter-timeline"
data-width="350"
data-theme="${themeQuality}"
data-chrome="nofooter noheader transparent"
data-tweet-limit="8"
href="https://twitter.com/EthereumRemix"
>
</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
`
yo.update(this.twitterFrame, twitterFrame)
const invertNum = (themeQuality === 'dark') ? 1 : 0
if (this.solEnv.getElementsByTagName('img')[0]) this.solEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.optimismEnv.getElementsByTagName('img')[0]) this.optimismEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.solhintEnv.getElementsByTagName('img')[0]) this.solhintEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.learnEthEnv.getElementsByTagName('img')[0]) this.learnEthEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.sourcifyEnv.getElementsByTagName('img')[0]) this.sourcifyEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.moreEnv.getElementsByTagName('img')[0]) this.moreEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.websiteIcon) this.websiteIcon.style.filter = `invert(${invertNum})`
}
showMediaPanel (e) {
if (e.target.id === 'remixIDEHomeTwitterbtn') {
this.mediumPanel.classList.remove('d-block')
this.mediumPanel.classList.add('d-none')
this.twitterPanel.classList.toggle('d-block')
_paq.push(['trackEvent', 'pluginManager', 'media', 'twitter'])
} else {
this.twitterPanel.classList.remove('d-block')
this.twitterPanel.classList.add('d-none')
this.mediumPanel.classList.toggle('d-block')
_paq.push(['trackEvent', 'pluginManager', 'media', 'medium'])
}
this.el = document.createElement('div')
this.el.setAttribute('id', 'landingPageHomeContainer')
this.el.setAttribute('class', 'remixui_homeContainer justify-content-between bg-light d-flex')
this.el.setAttribute('data-id', 'landingPageHomeContainer')
}
render () {
const load = (service, item, examples, info) => {
const contentImport = this.contentImport
const fileProviders = globalRegistry.get('fileproviders').api
const msg = yo`
<div class="p-2">
<span>Enter the ${item} you would like to load.</span>
<div>${info}</div>
<div>e.g ${examples.map((url) => { return yo`<div class="p-1"><a>${url}</a></div>` })}</div>
</div>`
const title = `Import from ${service}`
modalDialogCustom.prompt(title, msg, null, (target) => {
if (target !== '') {
contentImport.import(
target,
(loadingMsg) => { tooltip(loadingMsg) },
(error, content, cleanUrl, type, url) => {
if (error) {
modalDialogCustom.alert(title, error.message || error)
} else {
try {
fileProviders.workspace.addExternal(type + '/' + cleanUrl, content, url)
this.verticalIcons.select('filePanel')
} catch (e) {
modalDialogCustom.alert(title, e.message)
}
}
}
)
}
})
}
const startSolidity = async () => {
await this.appManager.activatePlugin(['solidity', 'udapp', 'solidityStaticAnalysis', 'solidityUnitTesting'])
this.verticalIcons.select('solidity')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'solidity'])
}
const startOptimism = async () => {
await this.appManager.activatePlugin('optimism-compiler')
this.verticalIcons.select('optimism-compiler')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'optimism-compiler'])
}
const startSolhint = async () => {
await this.appManager.activatePlugin(['solidity', 'solhint'])
this.verticalIcons.select('solhint')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'solhint'])
}
const startLearnEth = async () => {
await this.appManager.activatePlugin(['solidity', 'LearnEth', 'solidityUnitTesting'])
this.verticalIcons.select('LearnEth')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'learnEth'])
}
const startSourceVerify = async () => {
await this.appManager.activatePlugin(['solidity', 'source-verification'])
this.verticalIcons.select('source-verification')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'source-verification'])
}
const startPluginManager = async () => {
await this.appManager.activatePlugin('pluginManager')
this.verticalIcons.select('pluginManager')
}
const startRestoreBackupZip = async () => {
await this.appManager.activatePlugin(['restorebackupzip'])
this.verticalIcons.select('restorebackupzip')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'restorebackupzip'])
}
const createNewFile = () => {
this.call('filePanel', 'createNewFile')
}
const saveAs = (blob, name) => {
const node = document.createElement('a')
node.download = name
node.rel = 'noopener'
node.href = URL.createObjectURL(blob)
setTimeout(function () { URL.revokeObjectURL(node.href) }, 4E4) // 40s
setTimeout(function () {
try {
node.dispatchEvent(new MouseEvent('click'))
} catch (e) {
var evt = document.createEvent('MouseEvents')
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
20, false, false, false, false, 0, null)
node.dispatchEvent(evt)
}
}, 0) // 40s
}
const downloadFiles = async () => {
try {
tooltip('preparing files for download, please wait..')
const fileProviders = globalRegistry.get('fileproviders').api
const zip = new JSZip()
await fileProviders.browser.copyFolderToJson('/', ({ path, content }) => {
zip.file(`remixbackup${path}`, content)
})
zip.generateAsync({ type: 'blob' }).then(function (blob) {
saveAs(blob, 'remixbackup.zip')
}).catch((e) => {
tooltip(e.message)
})
} catch (e) {
tooltip(e.message)
}
}
const uploadFile = (target) => {
this.call('filePanel', 'uploadFile', target)
}
const connectToLocalhost = () => {
this.appManager.activatePlugin('remixd')
}
const importFromGist = () => {
this.gistHandler.loadFromGist({ gist: '' }, globalRegistry.get('filemanager').api)
this.verticalIcons.select('filePanel')
}
globalRegistry.get('themeModule').api.events.on('themeChanged', (theme) => {
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('remixLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('solidityLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('debuggerLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('learnEthLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('workshopLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('moreLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('solhintLogo'))
})
const createLargeButton = (imgPath, envID, envText, callback) => {
return yo`
<button
class="btn border-secondary d-flex mr-3 text-nowrap justify-content-center flex-column align-items-center ${css.envButton}"
data-id="landingPageStartSolidity"
onclick=${() => callback()}
>
<img class="m-2 align-self-center ${css.envLogo}" id=${envID} src="${imgPath}">
<label class="text-uppercase text-dark ${css.cursorStyle}">${envText}</label>
</button>
`
}
// main
this.solEnv = createLargeButton('assets/img/solidityLogo.webp', 'solidityLogo', 'Solidity', startSolidity)
// Featured
this.optimismEnv = createLargeButton('assets/img/optimismLogo.webp', 'optimismLogo', 'Optimism', startOptimism)
this.solhintEnv = createLargeButton('assets/img/solhintLogo.png', 'solhintLogo', 'Solhint linter', startSolhint)
this.learnEthEnv = createLargeButton('assets/img/learnEthLogo.webp', 'learnEthLogo', 'LearnEth', startLearnEth)
this.sourcifyEnv = createLargeButton('assets/img/sourcifyLogo.webp', 'sourcifyLogo', 'Sourcify', startSourceVerify)
this.moreEnv = createLargeButton('assets/img/moreLogo.webp', 'moreLogo', 'More', startPluginManager)
this.websiteIcon = yo`<img id='remixHhomeWebsite' class="mr-1 ${css.image}" src="${profile.icon}"></img>`
const themeQuality = globalRegistry.get('themeModule').api.currentTheme().quality
const invertNum = (themeQuality === 'dark') ? 1 : 0
this.solEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.optimismEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.solhintEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.learnEthEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.sourcifyEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.moreEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.websiteIcon.style.filter = `invert(${invertNum})`
const switchToPreviousVersion = () => {
const query = new QueryParams()
query.update({ appVersion: '0.7.7' })
_paq.push(['trackEvent', 'LoadingType', 'oldExperience_0.7.7'])
document.location.reload()
}
const migrate = async () => {
try {
setTimeout(() => {
tooltip('migrating workspace...')
}, 500)
const workspaceName = await migrateToWorkspace(this.fileManager, this.filePanel)
tooltip('done. ' + workspaceName + ' created.')
} catch (e) {
setTimeout(() => {
tooltip(e.message)
}, 1000)
}
}
const onAcceptDownloadn = async () => {
await downloadFiles()
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
migrate()
}
const onDownload = () => {
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
migrate()
}
const onCancel = () => {
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
}
const migrateWorkspace = async () => {
modalDialog(
'File system Migration',
yo`
<span>Do you want to download your files to local device first?</span>
<div class="d-flex justify-content-around pt-3 mt-3 border-top">
<button class="btn btn-sm btn-primary" onclick=${async () => onAcceptDownloadn()}>Download and Migrate</button>
<button class="btn btn-sm btn-secondary ${css.migrationBtn}" onclick=${() => onDownload()}>Migrate</button>
<button class="btn btn-sm btn-secondary ${css.migrationBtn}" onclick=${() => onCancel()}>Cancel</button>
</div>
`,
{
label: '',
fn: null
},
{
label: '',
fn: null
}
)
}
const img = yo`<img class="m-4 ${css.logoImg}" src="assets/img/guitarRemiCroped.webp" onclick="${() => playRemi()}"></img>`
const playRemi = async () => { await document.getElementById('remiAudio').play() }
// to retrieve medium posts
document.body.appendChild(yo`<script src="https://www.twilik.com/assets/retainable/rss-embed/retainable-rss-embed.js"></script>`)
const container = yo`
<div class="${css.homeContainer} d-flex" data-id="landingPageHomeContainer">
<div class="${css.mainContent} bg-light">
<div class="d-flex justify-content-between">
<div class="d-flex flex-column">
<div class="border-bottom d-flex justify-content-between clearfix py-3 mb-4">
<div class="mx-4 w-100 d-flex">
${img}
<audio id="remiAudio" muted=false src="assets/audio/remiGuitar-single-power-chord-A-minor.wav"></audio>
<div class="w-80 pl-5 ml-5">
<h5 class="mb-1">Quicklinks</h5>
<a class="${css.text} mr-1" target="__blank" href="https://medium.com/remix-ide/migrating-files-to-workspaces-8e34737c751c?source=friends_link&sk=b75cfd9093aa23c78be13cce49e4a5e8">Guide </a>for migrating the old File System
<p class="font-weight-bold mb-0 py-1">Migration tools:</p>
<li class="pl-1">
<spam class="pl-0">
<u class="${css.text} pr-1" onclick=${() => migrateWorkspace()}>Basic migration</u>
</spam>
</li>
<li class="pl-1">
<u class="${css.text} pr-1" onclick=${() => downloadFiles()}>Download all Files</u>
as a backup zip
</li>
<li class="pl-1">
<u class="${css.text} pr-1" onclick=${() => startRestoreBackupZip()}>Restore files</u>from backup zip
</li>
<p class="font-weight-bold mb-0 mt-2">Help:</p>
<dir class="d-flex flex-column mt-1 pl-0">
<a class="${css.text} mx-1" target="__blank" href="https://gitter.im/ethereum/remix">Gitter channel</a>
<a class="${css.text} mx-1" target="__blank" href="https://github.com/ethereum/remix-project/issues">Report on Github</a>
</dir>
</div>
</div>
</div>
<div class="row ${css.hpSections} mx-4" data-id="landingPageHpSections">
<div class="ml-3">
<div class="plugins mb-5">
<h4>Featured Plugins</h4>
<div class="d-flex flex-row pt-2">
${this.solEnv}
${this.optimismEnv}
${this.learnEthEnv}
${this.solhintEnv}
${this.sourcifyEnv}
${this.moreEnv}
</div>
</div>
<div class="d-flex">
<div class="file">
<h4>File</h4>
<p class="mb-1">
<i class="mr-1 far fa-file"></i>
<span class="ml-1 mb-1 ${css.text}" onclick=${() => createNewFile()}>New File</span>
</p>
<p class="mb-1">
<i class="mr-1 far fa-file-alt"></i>
<label class="ml-1 ${css.labelIt} ${css.bigLabelSize} ${css.text}">
Open Files
<input title="open file" type="file" onchange="${(event) => {
event.stopPropagation()
uploadFile(event.target)
}
}" multiple />
</label>
</p>
<p class="mb-1">
<i class="far fa-hdd"></i>
<span class="ml-1 ${css.text}" onclick=${() => connectToLocalhost()}>Connect to Localhost</span>
</p>
<p class="mt-3 mb-0"><label>LOAD FROM:</label></p>
<div class="btn-group">
<button class="btn mr-1 btn-secondary" data-id="landingPageImportFromGistButton" onclick="${() => importFromGist()}">Gist</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Github', 'github URL', ['https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol', 'https://github.com/OpenZeppelin/openzeppelin-solidity/blob/67bca857eedf99bf44a4b6a0fc5b5ed553135316/contracts/access/Roles.sol'])}">GitHub</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Ipfs', 'ipfs URL', ['ipfs://<ipfs-hash>'])}">Ipfs</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Https', 'http/https raw content', ['https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol'])}">https</button>
</div><!-- end of btn-group -->
</div><!-- end of div.file -->
<div class="ml-4 pl-4">
<h4>Resources</h4>
<p class="mb-1">
<i class="mr-1 fas fa-book"></i>
<a class="${css.text}" target="__blank" href="https://remix-ide.readthedocs.io/en/latest/#">Documentation</a>
</p>
<p class="mb-1">
<i class="mr-1 fab fa-gitter"></i>
<a class="${css.text}" target="__blank" href="https://gitter.im/ethereum/remix">Gitter channel</a>
</p>
<p class="mb-1">
${this.websiteIcon}
<a class="${css.text}" target="__blank" href="https://remix-project.org">Featuring website</a>
</p>
<p class="mb-1">
<i class="fab fa-ethereum ${css.image}"></i>
<span class="${css.text}" onclick=${() => switchToPreviousVersion()}>Old experience</span>
</p>
</div>
</div>
</div>
</div><!-- end of hpSections -->
</div>
<div class="d-flex flex-column ${css.rightPanel}">
<div class="d-flex pr-3 py-2 align-self-end" id="remixIDEMediaPanelsTitle">
${this.badgeTwitter}
${this.badgeMedium}
</div>
<div class="mr-3 d-flex bg-light ${css.panels}" id="remixIDEMediaPanels">
${this.mediumPanel}
${this.twitterPanel}
</div>
</div>
</div>
</div>
</div>
`
this.renderComponent()
return this.el
}
return container
renderComponent () {
ReactDOM.render(
<RemixUiHomeTab
plugin={this}
/>
, this.el)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -8,16 +8,6 @@ export class FramingService {
}
start (params) {
this.sidePanel.events.on('toggle', () => {
this.resizeFeature.panel.clientWidth !== 0 ? this.resizeFeature.hidePanel() : this.resizeFeature.showPanel()
})
this.sidePanel.events.on('showing', () => {
if (this.resizeFeature.panel.clientWidth === 0) this.resizeFeature.showPanel()
})
this.mainPanel.events.on('toggle', () => {
this.resizeFeature.showPanel()
})
this.verticalIcons.select('filePanel')
document.addEventListener('keypress', (e) => {

@ -56,6 +56,7 @@
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.7.0/introjs.min.css">
</head>
<body>
<div id="root"></div>
<script>
function urlParams () {
var qs = window.location.hash.substr(1)

@ -1,10 +0,0 @@
'use strict'
// require('@babel/polyfill')
var App = require('./app.js')
var app = new App({})
document.body.appendChild(app.render())
app.init() // @TODO: refactor to remove

@ -0,0 +1,16 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import ReactDOM from 'react-dom'
import AppComponent from './app'
// eslint-disable-next-line no-unused-vars
import { RemixApp } from '@remix-ui/app'
const appComponent = new AppComponent()
appComponent.run()
ReactDOM.render(
<React.StrictMode>
<RemixApp app={appComponent}></RemixApp>
</React.StrictMode>,
document.getElementById('root')
)

@ -56,6 +56,7 @@
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.7.0/introjs.min.css">
</head>
<body>
<div id="root"></div>
<script>
function urlParams () {
var qs = window.location.hash.substr(1)

@ -1,56 +1,66 @@
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
const introJs = require('intro.js')
export class WalkthroughService {
constructor (params) {
this.params = params
}
const profile = {
name: 'walkthrough',
displayName: 'Walkthrough',
description: '',
version: packageJson.version,
methods: ['start']
}
start (params) {
document.addEventListener('doWalkThrough', (e) => {
if (!localStorage.getItem('hadTour_initial')) {
introJs().setOptions({
steps: [{
title: 'Welcome to Remix IDE',
intro: 'Click to launch the Home tab that contains links, tips, and shortcuts..',
element: document.querySelector('#verticalIconsHomeIcon'),
tooltipClass: 'bg-light text-dark',
position: 'right'
},
{
element: document.querySelector('#compileIcons'),
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',
position: 'right'
},
{
title: 'Deploy your contract',
element: document.querySelector('#verticalIconsKindudapp'),
intro: 'Choose a chain, deploy a contract and play with your functions.',
tooltipClass: 'bg-light text-dark',
position: 'right'
}
]
}).onafterchange((targetElement) => {
const header = document.getElementsByClassName('introjs-tooltip-header')[0]
if (header) {
header.classList.add('d-flex')
header.classList.add('justify-content-between')
header.classList.add('text-nowrap')
header.classList.add('pr-0')
}
const skipbutton = document.getElementsByClassName('introjs-skipbutton')[0]
if (skipbutton) {
skipbutton.classList.add('ml-3')
skipbutton.classList.add('text-decoration-none')
skipbutton.id = 'remixTourSkipbtn'
}
}).start()
localStorage.setItem('hadTour_initial', true)
export class WalkthroughService extends Plugin {
constructor (appManager, showMatamo) {
super(profile)
appManager.event.on('activate', (plugin) => {
if (plugin.name === 'udapp' && !showMatamo) {
this.start()
}
})
}
startFeatureTour () {
start () {
if (!localStorage.getItem('hadTour_initial')) {
introJs().setOptions({
steps: [{
title: 'Welcome to Remix IDE',
intro: 'Click to launch the Home tab that contains links, tips, and shortcuts..',
element: document.querySelector('#verticalIconsHomeIcon'),
tooltipClass: 'bg-light text-dark',
position: 'right'
},
{
element: document.querySelector('#compileIcons'),
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',
position: 'right'
},
{
title: 'Deploy your contract',
element: document.querySelector('#verticalIconsKindudapp'),
intro: 'Choose a chain, deploy a contract and play with your functions.',
tooltipClass: 'bg-light text-dark',
position: 'right'
}
]
}).onafterchange((targetElement) => {
const header = document.getElementsByClassName('introjs-tooltip-header')[0]
if (header) {
header.classList.add('d-flex')
header.classList.add('justify-content-between')
header.classList.add('text-nowrap')
header.classList.add('pr-0')
}
const skipbutton = document.getElementsByClassName('introjs-skipbutton')[0]
if (skipbutton) {
skipbutton.classList.add('ml-3')
skipbutton.classList.add('text-decoration-none')
skipbutton.id = 'remixTourSkipbtn'
}
}).start()
localStorage.setItem('hadTour_initial', true)
}
}
}

@ -34,6 +34,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<body>
<div id="root"></div>
<script>
function urlParams () {
var qs = window.location.hash.substr(1)

@ -6,7 +6,8 @@
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"types": ["node", "jest"]
"types": ["node", "jest"],
"module": "es6",
},
"files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",

@ -0,0 +1,4 @@
{
"presets": ["@nrwl/react/babel"],
"plugins": []
}

@ -0,0 +1,248 @@
{
"rules": {
"array-callback-return": "warn",
"dot-location": ["warn", "property"],
"eqeqeq": ["warn", "smart"],
"new-parens": "warn",
"no-caller": "warn",
"no-cond-assign": ["warn", "except-parens"],
"no-const-assign": "warn",
"no-control-regex": "warn",
"no-delete-var": "warn",
"no-dupe-args": "warn",
"no-dupe-keys": "warn",
"no-duplicate-case": "warn",
"no-empty-character-class": "warn",
"no-empty-pattern": "warn",
"no-eval": "warn",
"no-ex-assign": "warn",
"no-extend-native": "warn",
"no-extra-bind": "warn",
"no-extra-label": "warn",
"no-fallthrough": "warn",
"no-func-assign": "warn",
"no-implied-eval": "warn",
"no-invalid-regexp": "warn",
"no-iterator": "warn",
"no-label-var": "warn",
"no-labels": ["warn", { "allowLoop": true, "allowSwitch": false }],
"no-lone-blocks": "warn",
"no-loop-func": "warn",
"no-mixed-operators": [
"warn",
{
"groups": [
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": false
}
],
"no-multi-str": "warn",
"no-native-reassign": "warn",
"no-negated-in-lhs": "warn",
"no-new-func": "warn",
"no-new-object": "warn",
"no-new-symbol": "warn",
"no-new-wrappers": "warn",
"no-obj-calls": "warn",
"no-octal": "warn",
"no-octal-escape": "warn",
"no-redeclare": "warn",
"no-regex-spaces": "warn",
"no-restricted-syntax": ["warn", "WithStatement"],
"no-script-url": "warn",
"no-self-assign": "warn",
"no-self-compare": "warn",
"no-sequences": "warn",
"no-shadow-restricted-names": "warn",
"no-sparse-arrays": "warn",
"no-template-curly-in-string": "warn",
"no-this-before-super": "warn",
"no-throw-literal": "warn",
"no-restricted-globals": [
"error",
"addEventListener",
"blur",
"close",
"closed",
"confirm",
"defaultStatus",
"defaultstatus",
"event",
"external",
"find",
"focus",
"frameElement",
"frames",
"history",
"innerHeight",
"innerWidth",
"length",
"location",
"locationbar",
"menubar",
"moveBy",
"moveTo",
"name",
"onblur",
"onerror",
"onfocus",
"onload",
"onresize",
"onunload",
"open",
"opener",
"opera",
"outerHeight",
"outerWidth",
"pageXOffset",
"pageYOffset",
"parent",
"print",
"removeEventListener",
"resizeBy",
"resizeTo",
"screen",
"screenLeft",
"screenTop",
"screenX",
"screenY",
"scroll",
"scrollbars",
"scrollBy",
"scrollTo",
"scrollX",
"scrollY",
"self",
"status",
"statusbar",
"stop",
"toolbar",
"top"
],
"no-unexpected-multiline": "warn",
"no-unreachable": "warn",
"no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-unused-labels": "warn",
"no-useless-computed-key": "warn",
"no-useless-concat": "warn",
"no-useless-escape": "warn",
"no-useless-rename": [
"warn",
{
"ignoreDestructuring": false,
"ignoreImport": false,
"ignoreExport": false
}
],
"no-with": "warn",
"no-whitespace-before-property": "warn",
"react-hooks/exhaustive-deps": "warn",
"require-yield": "warn",
"rest-spread-spacing": ["warn", "never"],
"strict": ["warn", "never"],
"unicode-bom": ["warn", "never"],
"use-isnan": "warn",
"valid-typeof": "warn",
"no-restricted-properties": [
"error",
{
"object": "require",
"property": "ensure",
"message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting"
},
{
"object": "System",
"property": "import",
"message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting"
}
],
"getter-return": "warn",
"import/first": "error",
"import/no-amd": "error",
"import/no-webpack-loader-syntax": "error",
"react/forbid-foreign-prop-types": ["warn", { "allowInPropTypes": true }],
"react/jsx-no-comment-textnodes": "warn",
"react/jsx-no-duplicate-props": "warn",
"react/jsx-no-target-blank": "warn",
"react/jsx-no-undef": "error",
"react/jsx-pascal-case": ["warn", { "allowAllCaps": true, "ignore": [] }],
"react/jsx-uses-react": "warn",
"react/jsx-uses-vars": "warn",
"react/no-danger-with-children": "warn",
"react/no-direct-mutation-state": "warn",
"react/no-is-mounted": "warn",
"react/no-typos": "error",
"react/react-in-jsx-scope": "error",
"react/require-render-return": "error",
"react/style-prop-object": "warn",
"react/jsx-no-useless-fragment": "warn",
"jsx-a11y/accessible-emoji": "warn",
"jsx-a11y/alt-text": "warn",
"jsx-a11y/anchor-has-content": "warn",
"jsx-a11y/anchor-is-valid": [
"warn",
{ "aspects": ["noHref", "invalidHref"] }
],
"jsx-a11y/aria-activedescendant-has-tabindex": "warn",
"jsx-a11y/aria-props": "warn",
"jsx-a11y/aria-proptypes": "warn",
"jsx-a11y/aria-role": "warn",
"jsx-a11y/aria-unsupported-elements": "warn",
"jsx-a11y/heading-has-content": "warn",
"jsx-a11y/iframe-has-title": "warn",
"jsx-a11y/img-redundant-alt": "warn",
"jsx-a11y/no-access-key": "warn",
"jsx-a11y/no-distracting-elements": "warn",
"jsx-a11y/no-redundant-roles": "warn",
"jsx-a11y/role-has-required-aria-props": "warn",
"jsx-a11y/role-supports-aria-props": "warn",
"jsx-a11y/scope": "warn",
"react-hooks/rules-of-hooks": "error",
"default-case": "off",
"no-dupe-class-members": "off",
"no-undef": "off",
"@typescript-eslint/consistent-type-assertions": "warn",
"no-array-constructor": "off",
"@typescript-eslint/no-array-constructor": "warn",
"@typescript-eslint/no-namespace": "error",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": [
"warn",
{
"functions": false,
"classes": false,
"variables": false,
"typedefs": false
}
],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{ "args": "none", "ignoreRestSiblings": true }
],
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": "warn"
},
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"jest": true,
"node": true
},
"settings": { "react": { "version": "detect" } },
"plugins": ["import", "jsx-a11y", "react", "react-hooks"],
"extends": ["../../../.eslintrc"],
"ignorePatterns": ["!**/*"]
}

@ -0,0 +1 @@
export { default as RemixApp } from './lib/remix-app/remix-app'

@ -0,0 +1,5 @@
import React from 'react'
const AppContext = React.createContext(null)
export default AppContext

@ -0,0 +1,26 @@
/* 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;
}

@ -0,0 +1,53 @@
import React, { useEffect, useState } from 'react'
import Draggable from 'react-draggable'
import './dragbar.css'
interface IRemixDragBarUi {
refObject: React.MutableRefObject<any>;
setHideStatus: (hide: boolean) => void;
hidden: boolean
minWidth: number
}
const DragBar = (props: IRemixDragBarUi) => {
const [dragState, setDragState] = useState<boolean>(false)
const [dragBarPosX, setDragBarPosX] = useState<number>(0)
const [offset, setOffSet] = useState<number>(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])
function stopDrag (e: MouseEvent, data: any) {
setDragState(false)
if (data.x < props.minWidth) {
setDragBarPosX(offset)
props.setHideStatus(true)
} else {
props.refObject.current.style.width = (data.x - offset) + 'px'
props.setHideStatus(false)
setDragBarPosX(offset + props.refObject.current.offsetWidth)
}
}
function startDrag () {
setDragState(true)
}
return <>
<div className={`overlay ${dragState ? '' : 'd-none'}`} ></div>
<Draggable nodeRef={nodeRef} position={{ x: dragBarPosX, y: 0 }} onStart={startDrag} onStop={stopDrag} axis="x">
<div ref={nodeRef} className={`dragbar ${dragState ? 'ondrag' : ''}`}></div>
</Draggable>
</>
}
export default DragBar

@ -0,0 +1,43 @@
import React, { useEffect, useState } from 'react'
import { ModalDialog } from '@remix-ui/modal-dialog'
const AlertModal = () => {
const [visible, setVisible] = useState<boolean>(true)
const [content, setContent] = useState<string>('')
useEffect(() => {
// check the origin and warn message
if (window.location.hostname === 'yann300.github.io') {
setContent('This UNSTABLE ALPHA branch of Remix has been moved to http://ethereum.github.io/remix-live-alpha.')
} else if (window.location.hostname === 'remix-alpha.ethereum.org' ||
(window.location.hostname === 'ethereum.github.io' && window.location.pathname.indexOf('/remix-live-alpha') === 0)) {
setContent('Welcome to the Remix alpha instance. Please use it to try out latest features. But use preferably https://remix.ethereum.org for any production work.')
} else if (window.location.protocol.indexOf('http') === 0 &&
window.location.hostname !== 'remix.ethereum.org' &&
window.location.hostname !== 'localhost' &&
window.location.hostname !== '127.0.0.1') {
setContent(`The Remix IDE has moved to http://remix.ethereum.org.\n
This instance of Remix you are visiting WILL NOT BE UPDATED.\n
Please make a backup of your contracts and start using http://remix.ethereum.org`)
}
setVisible(content !== '')
}, [])
const closeModal = async () => {
setVisible(false)
}
const handleModalOkClick = async () => {
setVisible(false)
}
return (<ModalDialog
handleHide={closeModal}
id="appAlert"
hide={!visible}
title="Alert"
okLabel="Ok"
okFn={ handleModalOkClick }
cancelLabel=""
cancelFn={closeModal}>{content}</ModalDialog>)
}
export default AlertModal

@ -0,0 +1,51 @@
import React, { useContext, useEffect, useState } from 'react'
import { ModalDialog } from '@remix-ui/modal-dialog'
import AppContext from '../context/context'
const _paq = window._paq = window._paq || []
const MatomoDialog = (props) => {
const { settings, showMatamo, appManager } = useContext(AppContext)
const [visible, setVisible] = useState<boolean>(props.hide)
useEffect(() => {
if (showMatamo) {
setVisible(true)
} else {
setVisible(false)
}
}, [])
const declineModal = async () => {
settings.updateMatomoAnalyticsChoice(false)
_paq.push(['optUserOut'])
appManager.call('walkthrough', 'start')
setVisible(false)
}
const hideModal = async () => {
setVisible(false)
}
const handleModalOkClick = async () => {
_paq.push(['forgetUserOptOut'])
// @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
settings.updateMatomoAnalyticsChoice(true)
appManager.call('walkthrough', 'start')
setVisible(false)
}
return (<ModalDialog
handleHide={hideModal}
id="matomoDialog"
hide={!visible}
title="Help us to improve Remix IDE"
okLabel="Accept"
okFn={ handleModalOkClick }
cancelLabel="Decline"
cancelFn={declineModal}>
<p>An Opt-in version of <a href="https://matomo.org" target="_blank" rel="noreferrer">Matomo</a>, an open source data analytics platform is being used to improve Remix IDE.</p>
<p>We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.</p>
<p>All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: <a href="https://matomo.ethereum.org/index.php?module=MultiSites&action=index&idSite=23&period=day&date=yesterday" target="_blank" rel="noreferrer">take a look</a>.</p>
<p>We do not collect nor store any personally identifiable information (PII).</p>
<p>For more info, see: <a href="https://medium.com/p/66ef69e14931/" target="_blank" rel="noreferrer">Matomo Analyitcs on Remix iDE</a>.</p>
<p>You can change your choice in the Settings panel anytime.</p>
</ModalDialog>)
}
export default MatomoDialog

@ -0,0 +1,16 @@
import React from 'react'
const RemixSplashScreen = (props) => {
return (<> <div style={{ display: props.hide ? 'none' : 'block' }} className='centered'>
<svg id="Ebene_2" data-name="Ebene 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105 100">
<path d="M91.84,35a.09.09,0,0,1-.1-.07,41,41,0,0,0-79.48,0,.09.09,0,0,1-.1.07C9.45,35,1,35.35,1,42.53c0,8.56,1,16,6,20.32,2.16,1.85,5.81,2.3,9.27,2.22a44.4,44.4,0,0,0,6.45-.68.09.09,0,0,0,.06-.15A34.81,34.81,0,0,1,17,45c0-.1,0-.21,0-.31a35,35,0,0,1,70,0c0,.1,0,.21,0,.31a34.81,34.81,0,0,1-5.78,19.24.09.09,0,0,0,.06.15,44.4,44.4,0,0,0,6.45.68c3.46.08,7.11-.37,9.27-2.22,5-4.27,6-11.76,6-20.32C103,35.35,94.55,35,91.84,35Z"/>
<path d="M52,74,25.4,65.13a.1.1,0,0,0-.1.17L51.93,91.93a.1.1,0,0,0,.14,0L78.7,65.3a.1.1,0,0,0-.1-.17L52,74A.06.06,0,0,1,52,74Z"/>
<path d="M75.68,46.9,82,45a.09.09,0,0,0,.08-.09,29.91,29.91,0,0,0-.87-6.94.11.11,0,0,0-.09-.08l-6.43-.58a.1.1,0,0,1-.06-.18l4.78-4.18a.13.13,0,0,0,0-.12,30.19,30.19,0,0,0-3.65-6.07.09.09,0,0,0-.11,0l-5.91,2a.1.1,0,0,1-.12-.14L72.19,23a.11.11,0,0,0,0-.12,29.86,29.86,0,0,0-5.84-4.13.09.09,0,0,0-.11,0l-4.47,4.13a.1.1,0,0,1-.17-.07l.09-6a.1.1,0,0,0-.07-.1,30.54,30.54,0,0,0-7-1.47.1.1,0,0,0-.1.07l-2.38,5.54a.1.1,0,0,1-.18,0l-2.37-5.54a.11.11,0,0,0-.11-.06,30,30,0,0,0-7,1.48.12.12,0,0,0-.07.1l.08,6.05a.09.09,0,0,1-.16.07L37.8,18.76a.11.11,0,0,0-.12,0,29.75,29.75,0,0,0-5.83,4.13.11.11,0,0,0,0,.12l2.59,5.6a.11.11,0,0,1-.13.14l-5.9-2a.11.11,0,0,0-.12,0,30.23,30.23,0,0,0-3.62,6.08.11.11,0,0,0,0,.12l4.79,4.19a.1.1,0,0,1-.06.17L23,37.91a.1.1,0,0,0-.09.07A29.9,29.9,0,0,0,22,44.92a.1.1,0,0,0,.07.1L28.4,47a.1.1,0,0,1,0,.18l-5.84,3.26a.16.16,0,0,0,0,.11,30.17,30.17,0,0,0,2.1,6.76c.32.71.67,1.4,1,2.08a.1.1,0,0,0,.06,0L52,68.16H52l26.34-8.78a.1.1,0,0,0,.06-.05,30.48,30.48,0,0,0,3.11-8.88.1.1,0,0,0-.05-.11l-5.83-3.26A.1.1,0,0,1,75.68,46.9Z"/>
</svg>
<div className="info-secondary splash">
REMIX IDE
</div>
</div></>)
}
export default RemixSplashScreen

@ -0,0 +1,90 @@
import React, { useContext, useEffect, useRef, useState } from 'react'
import './style/remix-app.css'
import RemixSplashScreen from './modals/splashscreen'
import MatomoDialog from './modals/matomo'
import AlertModal from './modals/alert'
import AppContext from './context/context'
import DragBar from './dragbar/dragbar'
interface IRemixAppUi {
app: any
}
const RemixApp = (props: IRemixAppUi) => {
const [appReady, setAppReady] = useState<boolean>(false)
const [hideSidePanel, setHideSidePanel] = useState<boolean>(false)
const sidePanelRef = useRef(null)
const mainPanelRef = useRef(null)
const iconPanelRef = useRef(null)
const hiddenPanelRef = useRef(null)
useEffect(() => {
if (sidePanelRef.current) {
if (props.app.sidePanel) {
sidePanelRef.current.appendChild(props.app.sidePanel.render())
}
}
if (mainPanelRef.current) {
if (props.app.mainview) {
mainPanelRef.current.appendChild(props.app.mainview.render())
}
}
if (iconPanelRef.current) {
if (props.app.menuicons) {
iconPanelRef.current.appendChild(props.app.menuicons.render())
}
}
if (hiddenPanelRef.current) {
if (props.app.hiddenPanel) {
hiddenPanelRef.current.appendChild(props.app.hiddenPanel.render())
}
}
async function activateApp () {
props.app.themeModule.initTheme(() => {
setAppReady(true)
props.app.activate()
setListeners()
})
}
if (props.app) {
activateApp()
}
}, [])
function setListeners () {
props.app.sidePanel.events.on('toggle', () => {
setHideSidePanel(prev => {
return !prev
})
})
props.app.sidePanel.events.on('showing', () => {
setHideSidePanel(false)
})
}
const components = {
iconPanel: <div ref={iconPanelRef} id="icon-panel" data-id="remixIdeIconPanel" className="iconpanel bg-light"></div>,
sidePanel: <div ref={sidePanelRef} id="side-panel" data-id="remixIdeSidePanel" className={`sidepanel border-right border-left ${hideSidePanel ? 'd-none' : ''}`}></div>,
mainPanel: <div ref={mainPanelRef} id="main-panel" data-id="remixIdeMainPanel" className='mainpanel'></div>,
hiddenPanel: <div ref={hiddenPanelRef}></div>
}
return (
<AppContext.Provider value={{ settings: props.app.settings, showMatamo: props.app.showMatamo, appManager: props.app.appManager }}>
<RemixSplashScreen hide={appReady}></RemixSplashScreen>
<AlertModal></AlertModal>
<MatomoDialog hide={!appReady}></MatomoDialog>
<div className={`remixIDE ${appReady ? '' : 'd-none'}`} data-id="remixIDE">
{components.iconPanel}
{components.sidePanel}
<DragBar minWidth={250} refObject={sidePanelRef} hidden={hideSidePanel} setHideStatus={setHideSidePanel}></DragBar>
{components.mainPanel}
</div>
{components.hiddenPanel}
</AppContext.Provider>
)
}
export default RemixApp

@ -0,0 +1,71 @@
html { box-sizing: border-box; }
*, *:before, *:after { box-sizing: inherit; }
body {
/* font: 14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; */
font-size : .8rem;
}
pre {
overflow-x: auto;
}
.remixIDE {
width : 100vw;
height : 100vh;
overflow : hidden;
flex-direction : row;
display : flex;
}
.mainpanel {
display : flex;
flex-direction : column;
overflow : hidden;
flex : 1;
min-width : 320px;
}
.iconpanel {
display : flex;
flex-direction : column;
overflow : hidden;
width : 50px;
user-select : none;
}
.sidepanel {
display : flex;
flex-direction : row-reverse;
width: 320px;
}
.highlightcode {
position : absolute;
z-index : 20;
background-color : var(--info);
}
.highlightcode_fullLine {
position : absolute;
z-index : 20;
background-color : var(--info);
opacity : 0.5;
}
.centered {
position : fixed;
top : 20%;
left : 45%;
width : 200px;
height : 200px;
}
.centered svg path {
fill: var(--secondary);
}
.centered svg polygon {
fill : var(--secondary);
}
.onboarding {
color : var(--text-info);
background-color : var(--info);
}
.matomoBtn {
width : 100px;
}
.splash {
text-align: center;
}

@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.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"]
}

@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*.spec.js",
"**/*.spec.jsx",
"**/*.d.ts"
]
}

@ -0,0 +1,133 @@
/* eslint-disable */
export const cairoConf = {
comments: {
lineComment: '#'
},
brackets: [
['{', '}'],
['[', ']'],
['(', ')'],
['%{', '%}']
],
autoClosingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: '%{', close: '%}' },
{ open: "'", close: "'", notIn: ['string', 'comment'] }
],
surroundingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: '%{', close: '%}' },
{ open: "'", close: "'" }
]
}
export const cairoLang = {
defaultToken: '',
tokenPostfix: '.cairo',
brackets: [
{ token: 'delimiter.curly', open: '{', close: '}' },
{ token: 'delimiter.parenthesis', open: '(', close: ')' },
{ token: 'delimiter.square', open: '[', close: ']' },
{ token: 'delimiter.curly', open: '%{', close: '%}' }
],
keywords: [
// control
'if',
'else',
'end',
// meta
'alloc_locals',
'as',
'assert',
'cast',
'const',
'dw',
'felt',
'from',
'func',
'import',
'let',
'local',
'member',
'nondet',
'return',
'static_assert',
'struct',
'tempvar',
'with_attr',
'with',
// register
'ap',
'fp',
// opcode
'call',
'jmp',
'ret',
'abs',
'rel'
],
operators: ['=', ':', '==', '++', '+', '-', '*', '**', '/', '&', '%', '_'],
// we include these common regular expressions
symbols: /[=><!~?:&|+\-*\/\^%]+/,
numberDecimal: /[+-]?[0-9]+/,
numberHex: /[+-]?0x[0-9a-fA-F]+/,
// The main tokenizer for our languages
tokenizer: {
root: [
// identifiers and keywords
[
/[a-zA-Z_]\w*/,
{
cases: {
'@keywords': { token: 'keyword.$0' },
'@default': 'identifier'
}
}
],
// whitespace
{ include: '@whitespace' },
// directives
[/^%[a-zA-Z]\w*/, 'tag'],
// delimiters and operators
[/[{}()\[\]]/, '@brackets'],
[/[<>](?!@symbols)/, '@brackets'],
[
/@symbols/,
{
cases: {
'@operators': 'delimiter',
'@default': ''
}
}
],
// numbers
[/(@numberHex)/, 'number.hex'],
[/(@numberDecimal)/, 'number'],
// strings
[/'[^']*'/, 'string']
],
whitespace: [
[/\s+/, 'white'],
[/(^#.*$)/, 'comment']
]
}
}

@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint
import Editor, { loader } from '@monaco-editor/react'
import { reducerActions, reducerListener, initialState } from './actions/editor'
import { language, conf } from './syntax'
import { cairoLang, cairoConf } from './cairoSyntax'
import './remix-ui-editor.css'
@ -273,7 +274,11 @@ export const EditorUI = (props: EditorUIProps) => {
const file = editorModelsState[props.currentFile]
editorRef.current.setModel(file.model)
editorRef.current.updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly })
if (file.language === 'sol') monacoRef.current.editor.setModelLanguage(file.model, 'remix-solidity')
if (file.language === 'sol') {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-solidity')
} else if (file.language === 'cairo') {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-cairo')
}
setAnnotationsbyFile(props.currentFile)
setMarkerbyFile(props.currentFile)
}, [props.currentFile])
@ -362,9 +367,13 @@ export const EditorUI = (props: EditorUIProps) => {
monacoRef.current = monaco
// Register a new language
monacoRef.current.languages.register({ id: 'remix-solidity' })
monacoRef.current.languages.register({ id: 'remix-cairo' })
// Register a tokens provider for the language
monacoRef.current.languages.setMonarchTokensProvider('remix-solidity', language)
monacoRef.current.languages.setLanguageConfiguration('remix-solidity', conf)
monacoRef.current.languages.setMonarchTokensProvider('remix-cairo', cairoLang)
monacoRef.current.languages.setLanguageConfiguration('remix-cairo', cairoConf)
}
return (

@ -59,5 +59,6 @@ export const getPathIcon = (path: string) => {
? 'fas fa-brackets-curly' : path.endsWith('.vy')
? 'fak fa-vyper-mono' : path.endsWith('.lex')
? 'fak fa-lexon' : path.endsWith('.contract')
? 'fab fa-ethereum' : 'far fa-file'
? 'fab fa-ethereum' : path.endsWith('.cairo')
? 'fab fa-ethereum' : 'far fa-file' // TODO: add cairo icon
}

@ -0,0 +1,4 @@
{
"presets": ["@nrwl/react/babel"],
"plugins": []
}

@ -0,0 +1,248 @@
{
"rules": {
"array-callback-return": "warn",
"dot-location": ["warn", "property"],
"eqeqeq": ["warn", "smart"],
"new-parens": "warn",
"no-caller": "warn",
"no-cond-assign": ["warn", "except-parens"],
"no-const-assign": "warn",
"no-control-regex": "warn",
"no-delete-var": "warn",
"no-dupe-args": "warn",
"no-dupe-keys": "warn",
"no-duplicate-case": "warn",
"no-empty-character-class": "warn",
"no-empty-pattern": "warn",
"no-eval": "warn",
"no-ex-assign": "warn",
"no-extend-native": "warn",
"no-extra-bind": "warn",
"no-extra-label": "warn",
"no-fallthrough": "warn",
"no-func-assign": "warn",
"no-implied-eval": "warn",
"no-invalid-regexp": "warn",
"no-iterator": "warn",
"no-label-var": "warn",
"no-labels": ["warn", { "allowLoop": true, "allowSwitch": false }],
"no-lone-blocks": "warn",
"no-loop-func": "warn",
"no-mixed-operators": [
"warn",
{
"groups": [
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": false
}
],
"no-multi-str": "warn",
"no-native-reassign": "warn",
"no-negated-in-lhs": "warn",
"no-new-func": "warn",
"no-new-object": "warn",
"no-new-symbol": "warn",
"no-new-wrappers": "warn",
"no-obj-calls": "warn",
"no-octal": "warn",
"no-octal-escape": "warn",
"no-redeclare": "warn",
"no-regex-spaces": "warn",
"no-restricted-syntax": ["warn", "WithStatement"],
"no-script-url": "warn",
"no-self-assign": "warn",
"no-self-compare": "warn",
"no-sequences": "warn",
"no-shadow-restricted-names": "warn",
"no-sparse-arrays": "warn",
"no-template-curly-in-string": "warn",
"no-this-before-super": "warn",
"no-throw-literal": "warn",
"no-restricted-globals": [
"error",
"addEventListener",
"blur",
"close",
"closed",
"confirm",
"defaultStatus",
"defaultstatus",
"event",
"external",
"find",
"focus",
"frameElement",
"frames",
"history",
"innerHeight",
"innerWidth",
"length",
"location",
"locationbar",
"menubar",
"moveBy",
"moveTo",
"name",
"onblur",
"onerror",
"onfocus",
"onload",
"onresize",
"onunload",
"open",
"opener",
"opera",
"outerHeight",
"outerWidth",
"pageXOffset",
"pageYOffset",
"parent",
"print",
"removeEventListener",
"resizeBy",
"resizeTo",
"screen",
"screenLeft",
"screenTop",
"screenX",
"screenY",
"scroll",
"scrollbars",
"scrollBy",
"scrollTo",
"scrollX",
"scrollY",
"self",
"status",
"statusbar",
"stop",
"toolbar",
"top"
],
"no-unexpected-multiline": "warn",
"no-unreachable": "warn",
"no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-unused-labels": "warn",
"no-useless-computed-key": "warn",
"no-useless-concat": "warn",
"no-useless-escape": "warn",
"no-useless-rename": [
"warn",
{
"ignoreDestructuring": false,
"ignoreImport": false,
"ignoreExport": false
}
],
"no-with": "warn",
"no-whitespace-before-property": "warn",
"react-hooks/exhaustive-deps": "warn",
"require-yield": "warn",
"rest-spread-spacing": ["warn", "never"],
"strict": ["warn", "never"],
"unicode-bom": ["warn", "never"],
"use-isnan": "warn",
"valid-typeof": "warn",
"no-restricted-properties": [
"error",
{
"object": "require",
"property": "ensure",
"message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting"
},
{
"object": "System",
"property": "import",
"message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting"
}
],
"getter-return": "warn",
"import/first": "error",
"import/no-amd": "error",
"import/no-webpack-loader-syntax": "error",
"react/forbid-foreign-prop-types": ["warn", { "allowInPropTypes": true }],
"react/jsx-no-comment-textnodes": "warn",
"react/jsx-no-duplicate-props": "warn",
"react/jsx-no-target-blank": "warn",
"react/jsx-no-undef": "error",
"react/jsx-pascal-case": ["warn", { "allowAllCaps": true, "ignore": [] }],
"react/jsx-uses-react": "warn",
"react/jsx-uses-vars": "warn",
"react/no-danger-with-children": "warn",
"react/no-direct-mutation-state": "warn",
"react/no-is-mounted": "warn",
"react/no-typos": "error",
"react/react-in-jsx-scope": "error",
"react/require-render-return": "error",
"react/style-prop-object": "warn",
"react/jsx-no-useless-fragment": "warn",
"jsx-a11y/accessible-emoji": "warn",
"jsx-a11y/alt-text": "warn",
"jsx-a11y/anchor-has-content": "warn",
"jsx-a11y/anchor-is-valid": [
"warn",
{ "aspects": ["noHref", "invalidHref"] }
],
"jsx-a11y/aria-activedescendant-has-tabindex": "warn",
"jsx-a11y/aria-props": "warn",
"jsx-a11y/aria-proptypes": "warn",
"jsx-a11y/aria-role": "warn",
"jsx-a11y/aria-unsupported-elements": "warn",
"jsx-a11y/heading-has-content": "warn",
"jsx-a11y/iframe-has-title": "warn",
"jsx-a11y/img-redundant-alt": "warn",
"jsx-a11y/no-access-key": "warn",
"jsx-a11y/no-distracting-elements": "warn",
"jsx-a11y/no-redundant-roles": "warn",
"jsx-a11y/role-has-required-aria-props": "warn",
"jsx-a11y/role-supports-aria-props": "warn",
"jsx-a11y/scope": "warn",
"react-hooks/rules-of-hooks": "error",
"default-case": "off",
"no-dupe-class-members": "off",
"no-undef": "off",
"@typescript-eslint/consistent-type-assertions": "warn",
"no-array-constructor": "off",
"@typescript-eslint/no-array-constructor": "warn",
"@typescript-eslint/no-namespace": "error",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": [
"warn",
{
"functions": false,
"classes": false,
"variables": false,
"typedefs": false
}
],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{ "args": "none", "ignoreRestSiblings": true }
],
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": "warn"
},
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"jest": true,
"node": true
},
"settings": { "react": { "version": "detect" } },
"plugins": ["import", "jsx-a11y", "react", "react-hooks"],
"extends": ["../../../.eslintrc"],
"ignorePatterns": ["!**/*"]
}

@ -0,0 +1,7 @@
# remix-ui-home-tab
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test remix-ui-home-tab` to execute the unit tests via [Jest](https://jestjs.io).

@ -0,0 +1 @@
export * from './lib/remix-ui-home-tab'

@ -0,0 +1,27 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useContext } from 'react'
import { ThemeContext } from '../themeContext'
interface PluginButtonProps {
imgPath: string,
envID: string,
envText: string,
callback: any
}
function PluginButton ({ imgPath, envID, envText, callback }: PluginButtonProps) {
const themeFilter = useContext(ThemeContext)
return (
<button
className="btn border-secondary d-flex mr-3 text-nowrap justify-content-center flex-column align-items-center remixui_envButton"
data-id={'landingPageStart' + envText}
onClick={() => callback()}
>
<img className="m-2 align-self-center remixui_envLogo" id={envID} src={imgPath} alt="" style={ { filter: themeFilter.filter } } />
<label className="text-uppercase text-dark remixui_cursorStyle">{envText}</label>
</button>
)
}
export default PluginButton

@ -0,0 +1,82 @@
.remixui_text {
cursor: pointer;
font-weight: normal;
max-width: 300px;
}
.remixui_text:hover {
cursor: pointer;
text-decoration: underline;
}
.remixui_homeContainer {
overflow-y: hidden;
overflow-y: auto;
flex-grow: 3;
}
.remixui_hpLogoContainer {
margin: 30px;
padding-right: 90px;
}
.remixui_mediaBadge {
font-size: 2em;
height: 2em;
width: 2em;
}
.remixui_mediaBadge:focus {
outline: none;
}
.remixui_image {
height: 1em;
width: 1em;
text-align: center;
}
.remixui_logoImg {
height: 10em;
}
.remixui_rightPanel {
right: 0;
position: absolute;
z-index: 3;
}
.remixui_remixHomeMedia {
overflow-y: auto;
overflow-x: hidden;
}
.remixui_panels {
box-shadow: 0px 0px 13px -7px;
}
.remixui_labelIt {
margin-bottom: 0;
}
.remixui_bigLabelSize {
font-size: 13px;
}
.remixui_seeAll {
margin-top: 7px;
white-space: nowrap;
}
.remixui_importFrom p {
margin-right: 10px;
}
.remixui_logoContainer img{
height: 150px;
opacity: 0.7;
}
.remixui_envLogo {
height: 16px;
}
.remixui_cursorStyle {
cursor: pointer;
}
.remixui_envButton {
width: 120px;
height: 70px;
}
.remixui_media {
overflow: hidden;
max-width: 400px;
transition: .5s ease-out;
z-index: 1000;
}
.remixui_migrationBtn {
width: 100px;
}

@ -0,0 +1,370 @@
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import './remix-ui-home-tab.css'
import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line
import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
import PluginButton from './components/pluginButton' // eslint-disable-line
import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params'
import { ThemeContext, themes } from './themeContext'
declare global {
interface Window {
_paq: any
}
}
const _paq = window._paq = window._paq || [] //eslint-disable-line
/* eslint-disable-next-line */
export interface RemixUiHomeTabProps {
plugin: any
}
const loadingInitialState = {
tooltip: '',
showModalDialog: false,
importSource: ''
}
const loadingReducer = (state = loadingInitialState, action) => {
return { ...state, tooltip: action.tooltip, showModalDialog: false, importSource: '' }
}
export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
const { plugin } = props
const fileManager = plugin.fileManager
const [state, setState] = useState<{
themeQuality: { filter: string, name: string },
showMediaPanel: 'none' | 'twitter' | 'medium',
showModalDialog: boolean,
modalInfo: { title: string, loadItem: string, examples: Array<string> },
importSource: string,
toasterMsg: string
}>({
themeQuality: themes.light,
showMediaPanel: 'none',
showModalDialog: false,
modalInfo: { title: '', loadItem: '', examples: [] },
importSource: '',
toasterMsg: ''
})
const processLoading = () => {
const contentImport = plugin.contentImport
const workspace = fileManager.getProvider('workspace')
contentImport.import(
state.importSource,
(loadingMsg) => dispatch({ tooltip: loadingMsg }),
(error, content, cleanUrl, type, url) => {
if (error) {
toast(error.message || error)
} else {
try {
workspace.addExternal(type + '/' + cleanUrl, content, url)
plugin.call('menuicons', 'select', 'filePanel')
} catch (e) {
toast(e.message)
}
}
}
)
setState(prevState => {
return { ...prevState, showModalDialog: false, importSource: '' }
})
}
const [, dispatch] = useReducer(loadingReducer, loadingInitialState)
const playRemi = async () => {
remiAudioEl.current.play()
}
const remiAudioEl = useRef(null)
const inputValue = useRef(null)
useEffect(() => {
plugin.call('theme', 'currentTheme').then((theme) => {
// update theme quality. To be used for for images
setState(prevState => {
return { ...prevState, themeQuality: theme.quality === 'dark' ? themes.dark : themes.light }
})
})
plugin.on('theme', 'themeChanged', (theme) => {
// update theme quality. To be used for for images
setState(prevState => {
return { ...prevState, themeQuality: theme.quality === 'dark' ? themes.dark : themes.light }
})
})
window.addEventListener('click', (event) => {
const target = event.target as Element
const id = target.id
if (id !== 'remixIDEHomeTwitterbtn' && id !== 'remixIDEHomeMediumbtn') {
// todo check event.target
setState(prevState => { return { ...prevState, showMediaPanel: 'none' } })
}
})
// to retrieve twitter feed
const scriptTwitter = document.createElement('script')
scriptTwitter.src = 'https://platform.twitter.com/widgets.js'
scriptTwitter.async = true
document.body.appendChild(scriptTwitter)
// to retrieve medium publications
const scriptMedium = document.createElement('script')
scriptMedium.src = 'https://www.twilik.com/assets/retainable/rss-embed/retainable-rss-embed.js'
scriptMedium.async = true
document.body.appendChild(scriptMedium)
return () => {
document.body.removeChild(scriptTwitter)
document.body.removeChild(scriptMedium)
}
}, [])
const toast = (message: string) => {
setState(prevState => {
return { ...prevState, toasterMsg: message }
})
}
const createNewFile = async () => {
await plugin.call('filePanel', 'createNewFile')
}
const uploadFile = async (target) => {
await plugin.call('filePanel', 'uploadFile', target)
}
const connectToLocalhost = () => {
plugin.appManager.activatePlugin('remixd')
}
const importFromGist = () => {
plugin.gistHandler.loadFromGist({ gist: '' }, fileManager)
plugin.verticalIcons.select('filePanel')
}
const switchToPreviousVersion = () => {
const query = new QueryParams()
query.update({ appVersion: '0.7.7' })
_paq.push(['trackEvent', 'LoadingType', 'oldExperience_0.7.7'])
document.location.reload()
}
const startSolidity = async () => {
await plugin.appManager.activatePlugin(['solidity', 'udapp', 'solidityStaticAnalysis', 'solidityUnitTesting'])
plugin.verticalIcons.select('solidity')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'solidity'])
}
const startOptimism = async () => {
await plugin.appManager.activatePlugin('optimism-compiler')
plugin.verticalIcons.select('optimism-compiler')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'optimism-compiler'])
}
const startSolhint = async () => {
await plugin.appManager.activatePlugin(['solidity', 'solhint'])
plugin.verticalIcons.select('solhint')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'solhint'])
}
const startLearnEth = async () => {
await plugin.appManager.activatePlugin(['solidity', 'LearnEth', 'solidityUnitTesting'])
plugin.verticalIcons.select('LearnEth')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'learnEth'])
}
const startSourceVerify = async () => {
await plugin.appManager.activatePlugin(['solidity', 'source-verification'])
plugin.verticalIcons.select('source-verification')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'source-verification'])
}
const startPluginManager = async () => {
await plugin.appManager.activatePlugin('pluginManager')
plugin.verticalIcons.select('pluginManager')
}
const showFullMessage = (title: string, loadItem: string, examples: Array<string>) => {
setState(prevState => {
return { ...prevState, showModalDialog: true, modalInfo: { title: title, loadItem: loadItem, examples: examples } }
})
}
const hideFullMessage = () => { //eslint-disable-line
setState(prevState => {
return { ...prevState, showModalDialog: false, importSource: '' }
})
}
const maxHeight = Math.max(window.innerHeight - 150, 250) + 'px'
const examples = state.modalInfo.examples.map((urlEl, key) => (<div key={key} className="p-1 user-select-auto"><a>{urlEl}</a></div>))
const elHeight = '4000px'
return (
<>
<ModalDialog
id='homeTab'
title={ 'Import from ' + state.modalInfo.title }
okLabel='Import'
hide={ !state.showModalDialog }
handleHide={ () => hideFullMessage() }
okFn={ () => processLoading() }
>
<div className="p-2 user-select-auto">
{ state.modalInfo.loadItem !== '' && <span>Enter the { state.modalInfo.loadItem } you would like to load.</span> }
{ state.modalInfo.examples.length !== 0 &&
<>
<div>e.g</div>
<div>
{ examples }
</div>
</> }
<input
ref={inputValue}
type='text'
name='prompt_text'
id='inputPrompt_text'
className="w-100 mt-1 form-control"
data-id="homeTabModalDialogCustomPromptText"
value={state.importSource}
onInput={(e) => {
setState(prevState => {
return { ...prevState, importSource: inputValue.current.value }
})
}}
/>
</div>
</ModalDialog>
<Toaster message={state.toasterMsg} />
<div className="d-flex flex-column ml-4" id="remixUiRightPanel">
<div className="border-bottom d-flex justify-content-between mr-4 pb-3 mb-3">
<div className="mx-4 my-4 d-flex">
<label style={ { fontSize: 'xxx-large', height: 'auto', alignSelf: 'flex-end' } }>Remix IDE</label>
</div>
<div className="mr-4 d-flex">
<img className="mt-4 mb-2 remixui_logoImg" src="assets/img/guitarRemiCroped.webp" onClick={ () => playRemi() } alt=""></img>
<audio
id="remiAudio"
muted={false}
src="assets/audio/remiGuitar-single-power-chord-A-minor.wav"
ref={remiAudioEl}
></audio>
</div>
</div>
<div className="row remixui_hpSections mx-2 mr-4" data-id="landingPageHpSections">
<div className="ml-3">
<div className="mb-5">
<h4>Featured Plugins</h4>
<div className="d-flex flex-row pt-2">
<ThemeContext.Provider value={ state.themeQuality }>
<PluginButton imgPath="assets/img/solidityLogo.webp" envID="solidityLogo" envText="Solidity" callback={() => startSolidity()} />
<PluginButton imgPath="assets/img/optimismLogo.webp" envID="optimismLogo" envText="Optimism" callback={() => startOptimism()} />
<PluginButton imgPath="assets/img/solhintLogo.webp" envID="solhintLogo" envText="Solhint linter" callback={() => startSolhint()} />
<PluginButton imgPath="assets/img/learnEthLogo.webp" envID="learnEthLogo" envText="LearnEth" callback={() => startLearnEth()} />
<PluginButton imgPath="assets/img/sourcifyLogo.webp" envID="sourcifyLogo" envText="Sourcify" callback={() => startSourceVerify()} />
<PluginButton imgPath="assets/img/moreLogo.webp" envID="moreLogo" envText="More" callback={startPluginManager} />
</ThemeContext.Provider>
</div>
</div>
<div className="d-flex">
<div className="file">
<h4>File</h4>
<p className="mb-1">
<i className="mr-2 far fa-file"></i>
<span className="ml-1 mb-1 remixui_text" onClick={() => createNewFile()}>New File</span>
</p>
<p className="mb-1">
<i className="mr-2 far fa-file-alt"></i>
<span className="ml-1 remixui_labelIt remixui_bigLabelSize} remixui_text">
Open Files
<input title="open file" type="file" onChange={(event) => {
event.stopPropagation()
uploadFile(event.target)
}} multiple />
</span>
</p>
<p className="mb-1">
<i className="mr-1 far fa-hdd"></i>
<span className="ml-1 remixui_text" onClick={() => connectToLocalhost()}>Connect to Localhost</span>
</p>
<p className="mt-3 mb-0"><label>LOAD FROM:</label></p>
<div className="btn-group">
<button className="btn mr-1 btn-secondary" data-id="landingPageImportFromGistButton" onClick={() => importFromGist()}>Gist</button>
<button className="btn mx-1 btn-secondary" data-id="landingPageImportFromGitHubButton" onClick={() => showFullMessage('Github', 'github URL', ['https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol', 'https://github.com/OpenZeppelin/openzeppelin-solidity/blob/67bca857eedf99bf44a4b6a0fc5b5ed553135316/contracts/access/Roles.sol'])}>GitHub</button>
<button className="btn mx-1 btn-secondary" onClick={() => showFullMessage('Ipfs', 'ipfs URL', ['ipfs://<ipfs-hash>'])}>Ipfs</button>
<button className="btn mx-1 btn-secondary" onClick={() => showFullMessage('Https', 'http/https raw content', ['https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol'])}>https</button>
</div>
</div>
<div className="ml-4 pl-4">
<h4>Resources</h4>
<p className="mb-1">
<i className="mr-2 fas fa-book"></i>
<a className="remixui_text" target="__blank" href="https://remix-ide.readthedocs.io/en/latest/#">Documentation</a>
</p>
<p className="mb-1">
<i className="mr-2 fab fa-gitter"></i>
<a className="remixui_text" target="__blank" href="https://gitter.im/ethereum/remix">Gitter channel</a>
</p>
<p className="mb-1">
<img id='remixHhomeWebsite' className="mr-2 remixui_image" src={ plugin.profile.icon } style={ { filter: state.themeQuality.filter } } alt=''></img>
<a className="remixui_text" target="__blank" href="https://remix-project.org">Featuring website</a>
</p>
<p className="mb-1">
<i className="mr-2 fab fa-ethereum remixui_image"></i>
<span className="remixui_text" onClick={() => switchToPreviousVersion()}>Old experience</span>
</p>
</div>
</div>
</div>
</div>
<div className="d-flex flex-column remixui_rightPanel">
<div className="d-flex pr-3 py-2 align-self-end" id="remixIDEMediaPanelsTitle">
<button
className="btn-info p-2 m-1 border rounded-circle remixui_mediaBadge fab fa-twitter"
id="remixIDEHomeTwitterbtn"
title="Twitter"
onClick={(e) => {
setState(prevState => {
return { ...prevState, showMediaPanel: state.showMediaPanel === 'twitter' ? 'none' : 'twitter' }
})
_paq.push(['trackEvent', 'pluginManager', 'media', 'twitter'])
}}
></button>
<button
className="btn-danger p-2 m-1 border rounded-circle remixui_mediaBadge fab fa-medium"
id="remixIDEHomeMediumbtn"
title="Medium blogs"
onClick={(e) => {
setState(prevState => {
return { ...prevState, showMediaPanel: state.showMediaPanel === 'medium' ? 'none' : 'medium' }
})
_paq.push(['trackEvent', 'pluginManager', 'media', 'medium'])
}}
></button>
</div>
<div className="mr-3 d-flex bg-light remixui_panels" style={ { visibility: state.showMediaPanel === 'none' ? 'hidden' : 'visible' } } id="remixIDEMediaPanels">
<div id="remixIDE_MediumBlock" className="p-2 mx-1 mt-3 mb-0 remixui_remixHomeMedia" style={ { maxHeight: maxHeight } }>
<div id="medium-widget" className="px-3 remixui_media" hidden={state.showMediaPanel !== 'medium'} style={ { maxHeight: elHeight } }>
<div
id="retainable-rss-embed"
data-rss="https://medium.com/feed/remix-ide"
data-maxcols="1"
data-layout="grid"
data-poststyle="external"
data-readmore="More..."
data-buttonclass="btn mb-3"
data-offset="-100"
>
</div>
</div>
</div>
<div id="remixIDE_TwitterBlock" className="p-2 mx-1 mt-3 mb-0 remixui_remixHomeMedia" hidden={state.showMediaPanel !== 'twitter'} style={ { maxHeight: maxHeight, marginRight: '28px' } } >
<div className="remixui_media" style={ { minHeight: elHeight } } >
<a className="twitter-timeline"
data-width="330"
data-theme={ state.themeQuality.name }
data-chrome="nofooter noheader transparent"
data-tweet-limit="18"
href="https://twitter.com/EthereumRemix"
>
</a>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default RemixUiHomeTab

@ -0,0 +1,16 @@
import React from 'react' // eslint-disable-line
export const themes = {
light: {
filter: 'invert(0)',
name: 'light'
},
dark: {
filter: 'invert(1)',
name: 'dark'
}
}
export const ThemeContext = React.createContext(
themes.dark // default value
)

@ -0,0 +1,16 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"files": [],
"include": [],
"references": [
{
"path": "./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"]
}

@ -34,7 +34,9 @@ export const ModalDialog = (props: ModalDialogProps) => {
modal.current.addEventListener('blur', handleBlur)
return () => {
modal.current.removeEventListener('blur', handleBlur)
if (modal.current) {
modal.current.removeEventListener('blur', handleBlur)
}
}
}
}, [modal.current])

@ -1,6 +1,6 @@
/* eslint-disable no-undef */
export interface ModalDialogProps {
id?: string
id: string
title?: string,
message?: string | JSX.Element,
okLabel?: string,

@ -106,6 +106,7 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
return (
<Fragment>
<ModalDialog
id='permissionsSettings'
handleHide={closeModal}
cancelFn={cancel}
hide={modalVisibility}

@ -7,6 +7,8 @@ import './remix-ui-settings.css'
import { ethereumVM, generateContractMetadat, personal, textWrapEventAction, useMatomoAnalytics, saveTokenToast, removeTokenToast } from './settingsAction'
import { initialState, toastInitialState, toastReducer, settingReducer } from './settingsReducer'
import { Toaster } from '@remix-ui/toaster'// eslint-disable-line
import { RemixUiThemeModule } from '@remix-ui/theme-module'
import { ThemeModule } from 'libs/remix-ui/theme-module/types/theme-module'
/* eslint-disable-next-line */
export interface RemixUiSettingsProps {
@ -14,16 +16,15 @@ export interface RemixUiSettingsProps {
editor: any,
_deps: any,
useMatomoAnalytics: boolean
themeModule: ThemeModule
}
export const RemixUiSettings = (props: RemixUiSettingsProps) => {
const [, dispatch] = useReducer(settingReducer, initialState)
const [state, dispatchToast] = useReducer(toastReducer, toastInitialState)
const [tokenValue, setTokenValue] = useState('')
const [themeName, setThemeName] = useState('')
useEffect(() => {
props._deps.themeModule.switchTheme()
const token = props.config.get('settings/gist-access-token')
if (token === undefined) {
props.config.set('settings/generate-contract-metadata', true)
@ -32,7 +33,7 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => {
if (token) {
setTokenValue(token)
}
}, [themeName, state.message])
}, [state.message])
useEffect(() => {
if (props.useMatomoAnalytics !== null) useMatomoAnalytics(props.config, props.useMatomoAnalytics, dispatch)
@ -64,11 +65,6 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => {
useMatomoAnalytics(props.config, event.target.checked, dispatch)
}
const onswitchTheme = (event, name) => {
props._deps.themeModule.switchTheme(name)
setThemeName(name)
}
const getTextClass = (key) => {
if (props.config.get(key)) {
return textDark
@ -155,32 +151,12 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => {
</div>
)
const themes = () => {
const themes = props._deps.themeModule.getThemes()
if (themes) {
return themes.map((aTheme, index) => (
<div className="radio custom-control custom-radio mb-1 form-check" key={index}>
<input type="radio" onChange={event => { onswitchTheme(event, aTheme.name) }} className="align-middle custom-control-input" name='theme' id={aTheme.name} data-id={`settingsTabTheme${aTheme.name}`} checked = {props._deps.themeModule.active === aTheme.name }/>
<label className="form-check-label custom-control-label" data-id={`settingsTabThemeLabel${aTheme.name}`} htmlFor={aTheme.name}>{aTheme.name} ({aTheme.quality})</label>
</div>
)
)
}
}
return (
<div>
{state.message ? <Toaster message= {state.message}/> : null}
{generalConfig()}
{gistToken()}
<div className="border-top">
<div className="card-body pt-3 pb-2">
<h6 className="card-title">Themes</h6>
<div className="card-text themes-container">
{themes()}
</div>
</div>
</div>
<RemixUiThemeModule themeModule={props._deps.themeModule} />
</div>
)
}

@ -0,0 +1,77 @@
import { 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<HTMLElement>) => {
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,
}
}

@ -152,13 +152,18 @@ element.style {
z-index : 999;
}
.dragbarDragging {
background-color: var(--primary);
border: 2px solid var(--primary);
}
.console {
cursor : pointer;
}
.dragbarHorizontal:hover {
background-color: #007AA6;
border:2px solid #007AA6;
background-color: var(--secondary);
border:2px solid var(--secondary);
}
.listenOnNetwork {
min-height: auto;

@ -17,6 +17,7 @@ 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<T = Element> extends SyntheticEvent<T, any> {
@ -25,13 +26,8 @@ export interface ClipboardEvent<T = Element> extends SyntheticEvent<T, any> {
export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const { call, _deps, on, config, event, gistHandler, version } = props.plugin
const [toggleDownUp, setToggleDownUp] = useState('fa-angle-double-down')
const [_cmdIndex, setCmdIndex] = useState(-1)
const [_cmdTemp, setCmdTemp] = useState('')
// dragable state
const [leftHeight, setLeftHeight] = useState<undefined | number>(undefined)
const [separatorYPosition, setSeparatorYPosition] = useState<undefined | number>(undefined)
const [dragging, setDragging] = useState(false)
const [newstate, dispatch] = useReducer(registerCommandReducer, initialState)
const [cmdHistory, cmdHistoryDispatch] = useReducer(addCommandHistoryReducer, initialState)
@ -78,6 +74,28 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
// terminal dragable
const leftRef = useRef(null)
const panelRef = useRef(null)
const terminalMenu = useRef(null)
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' })
@ -199,18 +217,8 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
}
const handleMinimizeTerminal = (e) => {
e.preventDefault()
e.stopPropagation()
if (toggleDownUp === 'fa-angle-double-down') {
setToggleDownUp('fa-angle-double-up')
event.trigger('resize', [])
} else {
const terminalTopOffset = config.get('terminal-top-offset')
event.trigger('resize', [terminalTopOffset])
setToggleDownUp('fa-angle-double-down')
}
}
const focusinput = () => {
inputEl.current.focus()
@ -283,53 +291,6 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
}
/* start of mouse events */
const mousedown = (event: MouseEvent) => {
setSeparatorYPosition(event.clientY)
leftRef.current.style.backgroundColor = '#007AA6'
leftRef.current.style.border = '2px solid #007AA6'
setDragging(true)
}
const onMouseMove: any = (e: MouseEvent) => {
e.preventDefault()
if (dragging && leftHeight && separatorYPosition) {
const newLeftHeight = leftHeight + separatorYPosition - e.clientY
setSeparatorYPosition(e.clientY)
setLeftHeight(newLeftHeight)
event.trigger('resize', [newLeftHeight + 32])
}
}
const onMouseUp = () => {
leftRef.current.style.backgroundColor = ''
leftRef.current.style.border = ''
setDragging(false)
}
/* end of mouse event */
useEffect(() => {
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
return () => {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
}
}, [onMouseMove, onMouseUp])
React.useEffect(() => {
if (panelRef) {
if (!leftHeight) {
setLeftHeight(panelRef.current.offsetHeight)
return
}
panelRef.current.style.height = `${leftHeight}px`
}
}, [leftHeight, setLeftHeight, panelRef])
/* block contents that gets rendered from scriptRunner */
const _blocksRenderer = (mode) => {
@ -471,9 +432,9 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
return (
<div style={{ height: '323px', flexGrow: 1 }} className='panel' ref={panelRef}>
<div className="bar">
<div className="dragbarHorizontal" onMouseDown={mousedown} ref={leftRef}></div>
<div className="menu border-top border-dark bg-light" data-id="terminalToggleMenu">
<i className={`mx-2 toggleTerminal fas ${toggleDownUp}`} data-id="terminalToggleIcon" onClick={ handleMinimizeTerminal }></i>
<div className={`dragbarHorizontal ${isDragging ? 'dragbarDragging' : ''}`} onMouseDown={handleDraggingStart} ref={leftRef}></div>
<div className="menu border-top border-dark bg-light" ref={terminalMenu} data-id="terminalToggleMenu">
<i className={`mx-2 toggleTerminal fas ${isOpen ? 'fa-angle-double-down' : 'fa-angle-double-up'}`} data-id="terminalToggleIcon" onClick={handleToggleTerminal}></i>
<div className="mx-2 console" id="clearConsole" data-id="terminalClearConsole" onClick={handleClearConsole} >
<i className="fas fa-ban" aria-hidden="true" title="Clear console"
></i>
@ -566,6 +527,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
</div>
</div>
<ModalDialog
id='terminal'
title={ modalState.title }
message={ modalState.message }
hide={ modalState.hide }

@ -0,0 +1,12 @@
{
"presets": [
[
"@nrwl/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}

@ -0,0 +1,18 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

@ -0,0 +1,7 @@
# remix-ui-theme-module
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test remix-ui-theme-module` to execute the unit tests via [Jest](https://jestjs.io).

@ -0,0 +1 @@
export * from './lib/remix-ui-theme-module';

@ -0,0 +1,106 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useEffect, useRef, useState } from 'react';
import { Theme, ThemeModule } from '../../types/theme-module';
import './remix-ui-theme-module.module.css';
/* eslint-disable-next-line */
export interface RemixUiThemeModuleProps {
themeModule: ThemeModule;
}
const defaultThemes = [
{
name: 'Dark',
quality: 'dark',
url: 'assets/css/themes/remix-dark_tvx1s2.css'
},
{
name: 'Light',
quality: 'light',
url: 'assets/css/themes/remix-light_powaqg.css'
},
{
name: 'Midcentury',
quality: 'light',
url: 'assets/css/themes/remix-midcentury_hrzph3.css'
},
{
name: 'Black',
quality: 'dark',
url: 'assets/css/themes/remix-black_undtds.css'
},
{
name: 'Candy',
quality: 'light',
url: 'assets/css/themes/remix-candy_ikhg4m.css'
},
{
name: 'Cerulean',
quality: 'light',
url: 'assets/css/themes/bootstrap-cerulean.min.css'
},
{
name: 'Flatly',
quality: 'light',
url: 'assets/css/themes/bootstrap-flatly.min.css'
},
{
name: 'Spacelab',
quality: 'light',
url: 'assets/css/themes/bootstrap-spacelab.min.css'
},
{
name: 'Cyborg',
quality: 'dark',
url: 'assets/css/themes/bootstrap-cyborg.min.css'
}
];
export function RemixUiThemeModule({ themeModule }: RemixUiThemeModuleProps) {
const [themeName, setThemeName] = useState('')
useEffect(() => {
themeModule.switchTheme()
}, [themeName, themeModule])
return (
<div className="border-top">
<div className="card-body pt-3 pb-2">
<h6 className="card-title">Themes</h6>
<div className="card-text themes-container">
{themeModule.getThemes()
? themeModule.getThemes().map((theme, idx) => (
<div
className="radio custom-control custom-radio mb-1 form-check"
key={idx}
>
<input
type="radio"
onChange={event => {
themeModule.switchTheme(theme.name);
setThemeName(theme.name);
}}
className="align-middle custom-control-input"
name="theme"
id={theme.name}
data-id={`settingsTabTheme${theme.name}`}
checked={themeModule.active === theme.name}
/>
<label
className="form-check-label custom-control-label"
data-id={`settingsTabThemeLabel${theme.name}`}
htmlFor={theme.name}
>
{theme.name} ({theme.quality})
</label>
</div>
))
: null}
</div>
</div>
</div>
)
}
export default RemixUiThemeModule;

@ -0,0 +1,20 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./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"]
}

@ -0,0 +1,47 @@
import { Plugin } from "@remixproject/engine/lib/abstract";
import { EventEmitter } from "events";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export class ThemeModule extends Plugin<any, any> {
currentThemeState: Record<string, unknown>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(registry: any);
events: EventEmitter;
_deps: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
config: any;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
_paq: any
element: HTMLDivElement;
// eslint-disable-next-line @typescript-eslint/ban-types
themes: {[key: string]: Theme};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
active: string;
forced: boolean;
render(): HTMLDivElement;
renderComponent(): void;
/** Return the active theme */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
currentTheme(): any;
/** Returns all themes as an array */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getThemes(): Theme[];
/**
* Init the theme
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
initTheme(callback: any): void;
/**
* Change the current theme
* @param {string} [themeName] - The name of the theme
*/
switchTheme(themeName?: string): void;
/**
* fixes the invertion for images since this should be adjusted when we switch between dark/light qualified themes
* @param {element} [image] - the dom element which invert should be fixed to increase visibility
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fixInvert(image?: any): void;
}
interface Theme { name: string, quality: string, url: string }

@ -92,6 +92,7 @@ export const Toaster = (props: ToasterProps) => {
return (
<>
<ModalDialog
id='toaster'
message={props.message}
cancelLabel='Close'
cancelFn={() => {}}

@ -130,17 +130,26 @@
"remix-ui-editor": {
"tags": []
},
"remix-ui-app": {
"tags": []
},
"remix-ui-helper": {
"tags": []
},
"remix-ui-vertical-icons-panel": {
"tags": []
},
"remix-ui-home-tab": {
"tags": []
},
"remix-ui-tabs": {
"tags": []
},
"remix-ui-panel": {
"tags": []
},
"remix-ui-theme-module": {
"tags": []
}
},
"targetDependencies": {

4589
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -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,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,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,remix-ui-plugin-manager,remix-ui-terminal,remix-ui-editor,remix-ui-app,remix-ui-tabs",
"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",
@ -87,6 +87,7 @@
"nightwatch_local_fileExplorer": "npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/fileExplorer.test.js --env=chrome",
"nightwatch_local_debugger": "npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/debugger_*.test.js --env=chrome",
"nightwatch_local_editor": "npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/editor.test.js --env=chrome",
"nightwatch_local_importFromGithub": "npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/importFromGithub.test.js --env=chrome",
"nightwatch_local_compiler": "npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/compiler_api.test.js --env=chrome",
"nightwatch_local_txListener": "npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/txListener.test.js --env=chrome",
"nightwatch_local_fileManager": "npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/fileManager_api.test.js --env=chrome",
@ -186,12 +187,14 @@
"react-beautiful-dnd": "^13.1.0",
"react-bootstrap": "^1.6.4",
"react-dom": "^17.0.2",
"react-draggable": "^4.4.4",
"react-tabs": "^3.2.2",
"regenerator-runtime": "0.13.7",
"selenium": "^2.20.0",
"signale": "^1.4.0",
"string-similarity": "^4.0.4",
"time-stamp": "^2.2.0",
"ts-loader": "^9.2.6",
"tslib": "^2.3.0",
"web3": "^1.5.1",
"winston": "^3.3.3",
@ -263,11 +266,8 @@
"eslint-config-prettier": "^6.11.0",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-import": "2.20.2",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-react": "7.23.1",
"eslint-plugin-react-hooks": "4.2.0",
"eslint-plugin-standard": "4.0.1",
"events": "^3.0.0",
"execr": "^1.0.1",

@ -64,11 +64,15 @@
"@remix-ui/renderer": ["libs/remix-ui/renderer/src/index.ts"],
"@remix-ui/terminal": ["libs/remix-ui/terminal/src/index.ts"],
"@remix-ui/plugin-manager": ["libs/remix-ui/plugin-manager/src/index.ts"],
"@remix-ui/home-tab": ["libs/remix-ui/home-tab/src/index.ts"],
"@remix-ui/editor": ["libs/remix-ui/editor/src/index.ts"],
"@remix-ui/tabs": ["libs/remix-ui/tabs/src/index.ts"],
"@remix-ui/helper": ["libs/remix-ui/helper/src/index.ts"],
"@remix-ui/vertical-icons-panel": ["libs/remix-ui/vertical-icons-panel/src/index.ts"],
"@remix-ui/panel": ["libs/remix-ui/panel/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/theme-module": ["libs/remix-ui/theme-module/src/index.ts"]
}
},
"exclude": ["node_modules", "tmp"]

@ -11,12 +11,18 @@
"importHelpers": true,
"target": "es2015",
"module": "commonjs",
"lib": ["es2017", "dom"],
"lib": [
"es2017",
"dom"
],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {},
"allowSyntheticDefaultImports": true
},
"exclude": ["node_modules", "tmp"]
"exclude": [
"node_modules",
"tmp"
]
}

@ -141,7 +141,9 @@
"options": {
"linter": "eslint",
"config": "apps/remix-ide/.eslintrc",
"files": ["apps/remix-ide/src/**/*.js"],
"files": [
"apps/remix-ide/src/**/*.js"
],
"exclude": [
"**/node_modules/**",
"apps/remix-ide/src/app/editor/mode-solidity.js",
@ -170,8 +172,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["apps/remix-ide-e2e/tsconfig.e2e.json"],
"exclude": ["**/node_modules/**", "!apps/remix-ide-e2e/**/*"]
"tsConfig": [
"apps/remix-ide-e2e/tsconfig.e2e.json"
],
"exclude": [
"**/node_modules/**",
"!apps/remix-ide-e2e/**/*"
]
}
}
}
@ -187,14 +194,21 @@
"options": {
"linter": "eslint",
"config": "libs/remix-analyzer/.eslintrc",
"tsConfig": ["libs/remix-analyzer/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "libs/remix-analyzer/test/**/*"]
"tsConfig": [
"libs/remix-analyzer/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"libs/remix-analyzer/test/**/*"
]
}
},
"test": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": ["./../../node_modules/.bin/npm-run-all test"],
"commands": [
"./../../node_modules/.bin/npm-run-all test"
],
"cwd": "libs/remix-analyzer"
}
},
@ -205,7 +219,9 @@
"tsConfig": "libs/remix-analyzer/tsconfig.lib.json",
"packageJson": "libs/remix-analyzer/package.json",
"main": "libs/remix-analyzer/src/index.ts",
"assets": ["libs/remix-analyzer/*.md"]
"assets": [
"libs/remix-analyzer/*.md"
]
}
}
}
@ -221,14 +237,21 @@
"options": {
"linter": "eslint",
"config": "libs/remix-astwalker/.eslintrc",
"tsConfig": ["libs/remix-astwalker/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "libs/remix-astwalker/tests/**/*"]
"tsConfig": [
"libs/remix-astwalker/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"libs/remix-astwalker/tests/**/*"
]
}
},
"test": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": ["./../../node_modules/.bin/npm-run-all test"],
"commands": [
"./../../node_modules/.bin/npm-run-all test"
],
"cwd": "libs/remix-astwalker"
}
},
@ -239,7 +262,9 @@
"tsConfig": "libs/remix-astwalker/tsconfig.lib.json",
"packageJson": "libs/remix-astwalker/package.json",
"main": "libs/remix-astwalker/src/index.ts",
"assets": ["libs/remix-astwalker/*.md"]
"assets": [
"libs/remix-astwalker/*.md"
]
}
}
}
@ -255,14 +280,21 @@
"options": {
"linter": "eslint",
"config": "libs/remix-debug/.eslintrc",
"tsConfig": ["libs/remix-debug/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "libs/remix-debug/test/**/*"]
"tsConfig": [
"libs/remix-debug/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"libs/remix-debug/test/**/*"
]
}
},
"test": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": ["./../../node_modules/.bin/npm-run-all test"],
"commands": [
"./../../node_modules/.bin/npm-run-all test"
],
"cwd": "libs/remix-debug"
}
},
@ -300,14 +332,21 @@
"options": {
"linter": "eslint",
"config": "libs/remix-lib/.eslintrc",
"tsConfig": ["libs/remix-lib/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "libs/remix-lib/test/**/*"]
"tsConfig": [
"libs/remix-lib/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"libs/remix-lib/test/**/*"
]
}
},
"test": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": ["./../../node_modules/.bin/npm-run-all test"],
"commands": [
"./../../node_modules/.bin/npm-run-all test"
],
"cwd": "libs/remix-lib"
}
},
@ -318,7 +357,9 @@
"tsConfig": "libs/remix-lib/tsconfig.lib.json",
"packageJson": "libs/remix-lib/package.json",
"main": "libs/remix-lib/src/index.ts",
"assets": ["libs/remix-lib/*.md"]
"assets": [
"libs/remix-lib/*.md"
]
}
}
}
@ -334,14 +375,21 @@
"options": {
"linter": "eslint",
"config": "libs/remix-simulator/.eslintrc",
"tsConfig": ["libs/remix-simulator/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "libs/remix-simulator/test/**/*"]
"tsConfig": [
"libs/remix-simulator/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"libs/remix-simulator/test/**/*"
]
}
},
"test": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": ["./../../node_modules/.bin/npm-run-all test"],
"commands": [
"./../../node_modules/.bin/npm-run-all test"
],
"cwd": "libs/remix-simulator"
}
},
@ -379,14 +427,20 @@
"options": {
"linter": "eslint",
"config": "libs/remix-solidity/.eslintrc",
"tsConfig": ["libs/remix-solidity/tsconfig.lib.json"],
"exclude": ["**/node_modules/**"]
"tsConfig": [
"libs/remix-solidity/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"test": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": ["./../../node_modules/.bin/npm-run-all test"],
"commands": [
"./../../node_modules/.bin/npm-run-all test"
],
"cwd": "libs/remix-solidity"
}
},
@ -397,7 +451,9 @@
"tsConfig": "libs/remix-solidity/tsconfig.lib.json",
"packageJson": "libs/remix-solidity/package.json",
"main": "libs/remix-solidity/src/index.ts",
"assets": ["libs/remix-solidity/*.md"]
"assets": [
"libs/remix-solidity/*.md"
]
}
}
}
@ -413,7 +469,9 @@
"options": {
"linter": "eslint",
"config": "libs/remix-tests/.eslintrc",
"tsConfig": ["libs/remix-tests/tsconfig.lib.json"],
"tsConfig": [
"libs/remix-tests/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"libs/remix-tests/tests/**/*",
@ -462,7 +520,9 @@
"options": {
"linter": "eslint",
"config": "libs/remix-url-resolver/.eslintrc",
"tsConfig": ["libs/remix-url-resolver/tsconfig.lib.json"],
"tsConfig": [
"libs/remix-url-resolver/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"libs/remix-url-resolver/tests/**/*"
@ -472,7 +532,9 @@
"test": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": ["./../../node_modules/.bin/npm-run-all test"],
"commands": [
"./../../node_modules/.bin/npm-run-all test"
],
"cwd": "libs/remix-url-resolver"
}
},
@ -483,7 +545,9 @@
"tsConfig": "libs/remix-url-resolver/tsconfig.lib.json",
"packageJson": "libs/remix-url-resolver/package.json",
"main": "libs/remix-url-resolver/src/index.ts",
"assets": ["libs/remix-url-resolver/*.md"]
"assets": [
"libs/remix-url-resolver/*.md"
]
}
}
}
@ -502,7 +566,10 @@
"libs/remixd/tsconfig.lib.json",
"libs/remixd/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**", "!libs/remixd/**/*"]
"exclude": [
"**/node_modules/**",
"!libs/remixd/**/*"
]
}
},
"test": {
@ -520,7 +587,10 @@
"tsConfig": "libs/remixd/tsconfig.lib.json",
"packageJson": "libs/remixd/package.json",
"main": "libs/remixd/src/index.ts",
"assets": ["libs/remixd/*.md", "libs/remixd/src/origins.json"]
"assets": [
"libs/remixd/*.md",
"libs/remixd/src/origins.json"
]
}
}
}
@ -539,7 +609,10 @@
"libs/remix-ui/tree-view/tsconfig.lib.json",
"libs/remix-ui/tree-view/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**", "!libs/remix-ui/tree-view/**/*"]
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/tree-view/**/*"
]
}
},
"test": {
@ -566,7 +639,10 @@
"libs/remix-ui/debugger-ui/tsconfig.lib.json",
"libs/remix-ui/debugger-ui/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**", "!libs/remix-ui/debugger-ui/**/*"]
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/debugger-ui/**/*"
]
}
},
"test": {
@ -593,7 +669,10 @@
"libs/remix-ui/utils/tsconfig.lib.json",
"libs/remix-ui/utils/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**", "!libs/remix-ui/utils/**/*"]
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/utils/**/*"
]
}
},
"test": {
@ -620,7 +699,10 @@
"libs/remix-ui/clipboard/tsconfig.lib.json",
"libs/remix-ui/clipboard/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**", "!libs/remix-ui/clipboard/**/*"]
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/clipboard/**/*"
]
}
},
"test": {
@ -673,8 +755,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/toaster/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/toaster/**/*"]
"tsConfig": [
"libs/remix-ui/toaster/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/toaster/**/*"
]
}
}
}
@ -742,8 +829,13 @@
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["apps/debugger/tsconfig.app.json"],
"exclude": ["**/node_modules/**", "!apps/debugger/**/*"]
"tsConfig": [
"apps/debugger/tsconfig.app.json"
],
"exclude": [
"**/node_modules/**",
"!apps/debugger/**/*"
]
}
}
}
@ -758,8 +850,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/workspace/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/workspace/**/*"]
"tsConfig": [
"libs/remix-ui/workspace/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/workspace/**/*"
]
}
}
}
@ -774,8 +871,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/settings/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/settings/**/*"]
"tsConfig": [
"libs/remix-ui/settings/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/settings/**/*"
]
}
}
}
@ -790,7 +892,9 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/static-analyser/tsconfig.lib.json"],
"tsConfig": [
"libs/remix-ui/static-analyser/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/static-analyser/**/*"
@ -809,8 +913,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/checkbox/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/checkbox/**/*"]
"tsConfig": [
"libs/remix-ui/checkbox/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/checkbox/**/*"
]
}
}
}
@ -825,14 +934,19 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/terminal/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/terminal/**/*"]
"tsConfig": [
"libs/remix-ui/terminal/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/terminal/**/*"
]
}
}
}
},
"remix-ui-plugin-manager": {
"root": "libs/remix-ui/plugin-manager",
"root": "libs/remix-ui/plugin-manager",
"sourceRoot": "libs/remix-ui/plugin-manager/src",
"projectType": "library",
"schematics": {},
@ -841,7 +955,9 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/plugin-manager/tsconfig.lib.json"],
"tsConfig": [
"libs/remix-ui/plugin-manager/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/plugin-manager/**/*"
@ -860,8 +976,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-core-plugin/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-core-plugin/**/*"]
"tsConfig": [
"libs/remix-core-plugin/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-core-plugin/**/*"
]
}
},
"build": {
@ -885,7 +1006,9 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/solidity-compiler/tsconfig.lib.json"],
"tsConfig": [
"libs/remix-ui/solidity-compiler/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/solidity-compiler/**/*"
@ -904,7 +1027,9 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/publish-to-storage/tsconfig.lib.json"],
"tsConfig": [
"libs/remix-ui/publish-to-storage/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/publish-to-storage/**/*"
@ -923,8 +1048,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/renderer/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/renderer/**/*"]
"tsConfig": [
"libs/remix-ui/renderer/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/renderer/**/*"
]
}
}
}
@ -948,7 +1078,9 @@
"apps/solidity-compiler/src/assets",
"apps/solidity-compiler/src/index.html"
],
"styles": ["apps/solidity-compiler/src/styles.css"],
"styles": [
"apps/solidity-compiler/src/styles.css"
],
"scripts": [],
"webpackConfig": "apps/solidity-compiler/webpack.config.js",
"maxWorkers": 2
@ -993,8 +1125,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["apps/solidity-compiler/tsconfig.app.json"],
"exclude": ["**/node_modules/**", "!apps/solidity-compiler/**/*"]
"tsConfig": [
"apps/solidity-compiler/tsconfig.app.json"
],
"exclude": [
"**/node_modules/**",
"!apps/solidity-compiler/**/*"
]
}
}
}
@ -1017,7 +1154,9 @@
"apps/remix-ide-e2e/src/local-plugin/src/favicon.ico",
"apps/remix-ide-e2e/src/local-plugin/src/assets"
],
"styles": ["apps/remix-ide-e2e/src/local-plugin/src/styles.css"],
"styles": [
"apps/remix-ide-e2e/src/local-plugin/src/styles.css"
],
"scripts": [],
"webpackConfig": "@nrwl/react/plugins/webpack"
},
@ -1073,6 +1212,27 @@
}
}
},
"remix-ui-home-tab": {
"root": "libs/remix-ui/home-tab",
"sourceRoot": "libs/remix-ui/home-tab/src",
"projectType": "library",
"schematics": {},
"architect": {
"lint": {
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": [
"libs/remix-ui/home-tab/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/home-tab/**/*"
]
}
}
}
},
"remix-ui-editor": {
"root": "libs/remix-ui/editor",
"sourceRoot": "libs/remix-ui/editor/src",
@ -1083,8 +1243,54 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/editor/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/editor/**/*"]
"tsConfig": [
"libs/remix-ui/editor/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/editor/**/*"
]
}
}
}
},
"remix-ui-theme-module": {
"root": "libs/remix-ui/theme-module",
"sourceRoot": "libs/remix-ui/theme-module/src",
"projectType": "library",
"architect": {
"lint": {
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": [
"libs/remix-ui/editor/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/editor/**/*"
]
}
}
}
},
"remix-ui-app": {
"root": "libs/remix-ui/app",
"sourceRoot": "libs/remix-ui/app/src",
"projectType": "library",
"schematics": {},
"architect": {
"lint": {
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": [
"libs/remix-ui/app/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/app/**/*"
]
}
}
}
@ -1099,8 +1305,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/helper/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/helper/**/*"]
"tsConfig": [
"libs/remix-ui/helper/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/helper/**/*"
]
}
}
}
@ -1114,8 +1325,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/tabs/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/tabs/**/*"]
"tsConfig": [
"libs/remix-ui/tabs/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/tabs/**/*"
]
}
}
}
@ -1129,8 +1345,13 @@
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/vertical-icons-panel/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/vertical-icons-panel/**/*"]
"tsConfig": [
"libs/remix-ui/vertical-icons-panel/tsconfig.lib.json"
],
"exclude": [
"**/node_modules/**",
"!libs/remix-ui/vertical-icons-panel/**/*"
]
}
}
}

Loading…
Cancel
Save