Merge branch 'master' of https://github.com/ethereum/remix-project into panels
commit
3b0f422635
@ -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() |
||||||
|
} |
||||||
|
} |
Before Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.5 KiB |
@ -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') |
||||||
|
) |
@ -1,56 +1,66 @@ |
|||||||
|
import { Plugin } from '@remixproject/engine' |
||||||
|
import * as packageJson from '../../../package.json' |
||||||
const introJs = require('intro.js') |
const introJs = require('intro.js') |
||||||
|
|
||||||
export class WalkthroughService { |
const profile = { |
||||||
constructor (params) { |
name: 'walkthrough', |
||||||
this.params = params |
displayName: 'Walkthrough', |
||||||
} |
description: '', |
||||||
|
version: packageJson.version, |
||||||
|
methods: ['start'] |
||||||
|
} |
||||||
|
|
||||||
start (params) { |
export class WalkthroughService extends Plugin { |
||||||
document.addEventListener('doWalkThrough', (e) => { |
constructor (appManager, showMatamo) { |
||||||
if (!localStorage.getItem('hadTour_initial')) { |
super(profile) |
||||||
introJs().setOptions({ |
appManager.event.on('activate', (plugin) => { |
||||||
steps: [{ |
if (plugin.name === 'udapp' && !showMatamo) { |
||||||
title: 'Welcome to Remix IDE', |
this.start() |
||||||
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) |
|
||||||
} |
} |
||||||
}) |
}) |
||||||
} |
} |
||||||
|
|
||||||
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) |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -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'] |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -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"] |
||||||
|
} |
@ -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, |
||||||
|
} |
||||||
|
} |
@ -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 } |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue