implemented minimize terminal window and added custom hook

pull/1342/head
tizah 3 years ago committed by davidzagi93@gmail.com
parent a7fdf6f40f
commit 2bd05d70c6
  1. 6
      apps/remix-ide/src/app/panels/terminal.js
  2. 29
      libs/remix-ui/terminal/src/lib/custom-hooks/useKeyPress.tsx
  3. 4
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.css
  4. 242
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
  5. 19
      package-lock.json
  6. 3
      package.json

@ -34,11 +34,13 @@ class Terminal extends Plugin {
constructor (opts, api) {
super(profile)
this.element = document.createElement('div')
this.element.setAttribute('id', 'terminalView')
this.element.setAttribute('class', 'panel_2A0YE0')
this.element.setAttribute('id', 'terminal-view')
this.event = new EventManager()
this.blockchain = opts.blockchain
this._api = api
this._opts = opts
this.version = packageJson.version
this.data = {
lineLength: opts.lineLength || 80, // ????
session: [],
@ -122,6 +124,8 @@ class Terminal extends Plugin {
cmdInterpreter = {this._components.cmdInterpreter}
autoCompletePopup = {this._components.autoCompletePopup}
registerCommand = {this.registerCommand}
command = {this.commands}
version = {this.version}
/>,
this.element
)

@ -0,0 +1,29 @@
import React, {useEffect, useState} from "react" // eslint-disable-line
export const useKeyPress = (targetKey: string): boolean => {
// State for keeping track of whether key is pressed
const [keyPressed, setKeyPressed] = useState(false)
// If pressed key is our target key then set to true
function downHandler ({ key }): void {
if (key === targetKey) {
setKeyPressed(true)
}
}
// If released key is our target key then set to false
const upHandler = ({ key }): void => {
if (key === targetKey) {
setKeyPressed(false)
}
}
// Add event listeners
useEffect(() => {
window.addEventListener('keydown', downHandler)
window.addEventListener('keyup', upHandler)
// Remove event listeners on cleanup
return () => {
window.removeEventListener('keydown', downHandler)
window.removeEventListener('keyup', upHandler)
}
}, []) // Empty array ensures that effect is only run on mount and unmount
return keyPressed
}

@ -1,3 +1,7 @@
element.style {
height: 323px !important;
}
.panel {
position : relative;
display : flex;

@ -1,4 +1,6 @@
import React, { useState, useEffect, useRef, SyntheticEvent } from 'react' // eslint-disable-line
import { useKeyPress } from './custom-hooks/useKeyPress'
import { useWindowResize } from 'beautiful-react-hooks'
import './remix-ui-terminal.css'
@ -14,6 +16,14 @@ export interface RemixUiTerminalProps {
data: any
cmdInterpreter: any
registerCommand: any
command: any
version: any
// blockRenderHtml: any
// blockRenderLog: any
// blockRenderInfo: any
// blockRenderWarn: any
// blockRenderError: any
}
export interface ClipboardEvent<T = Element> extends SyntheticEvent<T, any> {
@ -24,8 +34,40 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const [toggleDownUp, setToggleDownUp] = useState('fa-angle-double-down')
const [inserted, setInserted] = useState(false)
const [_cmdIndex, setCmdIndex] = useState(-1)
const [_cmdTemp, setCmdTemp] = useState('')
const [_cmdHistory, setCmdHistory] = useState([])
const [windowHeight, setWindowHeight] = useState(window.innerHeight)
const [state, setState] = useState({
journalBlocks: {
intro: (
<div>
<div> - Welcome to Remix {props.version} - </div>
<br/>
<div>You can use this terminal to: </div>
<ul className='ul'>
<li>Check transactions details and start debugging.</li>
<li>Execute JavaScript scripts:
<br />
<i> - Input a script directly in the command line interface </i>
<br />
<i> - Select a Javascript file in the file explorer and then run \`remix.execute()\` or \`remix.exeCurrent()\` in the command line interface </i>
<br />
<i> - Right click on a JavaScript file in the file explorer and then click \`Run\` </i>
</li>
</ul>
<div>The following libraries are accessible:</div>
<ul className='ul'>
<li><a target="_blank" href="https://web3js.readthedocs.io/en/1.0/">web3 version 1.0.0</a></li>
<li><a target="_blank" href="https://docs.ethers.io">ethers.js</a> </li>
<li><a target="_blank" href="https://www.npmjs.com/package/swarmgw">swarmgw</a> </li>
<li>remix (run remix.help() for more info)</li>
</ul>
</div>
),
text: (<div>David</div>)
},
data: {
// lineLength: props.options.lineLength || 80,
session: [],
@ -43,6 +85,15 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
_INDEXcommandsMain: {}
})
const _scopedCommands = () => {
}
useWindowResize(() => {
setWindowHeight(window.innerHeight)
})
// terminal inputRef
const inputEl = useRef(null)
// events
@ -59,6 +110,16 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
// }
}, [])
const placeCaretAtEnd = (el) => {
el.focus()
const range = document.createRange()
range.selectNodeContents(el)
range.collapse(false)
const sel = window.getSelection()
sel.removeAllRanges()
sel.addRange(range)
}
// handle events
const handlePaste = (event: ClipboardEvent<HTMLInputElement>) => {
// Do something
@ -66,27 +127,28 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
if (!selection.rangeCount) return false
event.preventDefault()
event.stopPropagation()
var clipboard = (event.clipboardData) // || window.clipboardData
var text = clipboard.getData('text/plain')
const clipboard = (event.clipboardData) // || window.clipboardData
let text = clipboard.getData('text/plain')
text = text.replace(/[^\x20-\xFF]/gi, '') // remove non-UTF-8 characters
var temp = document.createElement('div')
const temp = document.createElement('div')
temp.innerHTML = text
var textnode = document.createTextNode(temp.textContent)
const textnode = document.createTextNode(temp.textContent)
selection.getRangeAt(0).insertNode(textnode)
selection.empty()
// self.scroll2bottom()
// placeCaretAtEnd(event.currentTarget)
placeCaretAtEnd(event.currentTarget)
}
const handleMinimizeTerminal = (event) => {
console.log('clikced', props.event)
event.preventDefault()
event.stopPropagation()
if (toggleDownUp === 'fa-angle-double-down') {
console.log('clikced down')
setToggleDownUp('fa-angle-double-up')
props.event.trigger.resize('resize', [])
props.event.trigger('resize', [])
} else {
console.log('clikced up')
// event.trigger('resize', [])
props.event.trigger('resize', [118])
setToggleDownUp('fa-angle-double-down')
}
console.log(props.event, 'event.trigger')
@ -161,24 +223,151 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
inputEl.current.focus()
}
const putCursor2End = (editable) => {
var range = document.createRange()
console.log({ range })
range.selectNode(editable)
var child = editable
var chars
console.log({ child })
while (child) {
if (child.lastChild) child = child.lastChild
else break
if (child.nodeType === Node.TEXT_NODE) {
chars = child.textContent.length
} else {
chars = child.innerHTML.length
}
}
range.setEnd(child, chars)
var toStart = true
var toEnd = !toStart
range.collapse(toEnd)
var sel = window.getSelection()
sel.removeAllRanges()
sel.addRange(range)
editable.focus()
}
const wrapScript = (script) => {
const isKnownScript = ['remix.', 'git'].some(prefix => script.trim().startsWith(prefix))
if (isKnownScript) return script
return `
try {
const ret = ${script};
if (ret instanceof Promise) {
ret.then((result) => { console.log(result) }).catch((error) => { console.log(error) })
} else {
console.log(ret)
}
} catch (e) {
console.log(e.message)
}`
}
const handleKeyDown = (event) => {
if (props.autoCompletePopup.handleAutoComplete(
event,
inputEl.current.innerText)) { return }
if (inputEl.current.innerText.length === 0) {
inputEl.current.innerText += '\n'
}
if (event.which === 13) {
if (event.ctrlKey) { // <ctrl+enter>
// on enter, append the value in the cli input to the journal
// setState(prevState => ({...prevState.journalBlocks, prevState: inputEl})
inputEl.current.innerText += '\n'
inputEl.current.focus()
// putCursor2End(inputEl.current)
// scroll2botton () function not implemented
props.autoCompletePopup.removeAutoComplete()
} else {
setCmdIndex(-1)
setCmdTemp('')
const script = inputEl.current.innerText.trim()
console.log({ script })
inputEl.current.innerText += '\n'
if (script.length) {
// self._cmdHistory.unshift(script)
props.command.script(wrapScript(script))
}
props.autoCompletePopup.removeAutoComplete()
}
} else if (event.which === 38) { // <arrowUp>
const len = _cmdHistory.length
if (len === 0) event.preventDefault()
if (_cmdHistory.length - 1 > _cmdIndex) {
setCmdIndex(prevState => prevState++)
}
inputEl.current.innerText = _cmdHistory[_cmdIndex]
inputEl.current.focus()
// putCursor2End(inputEl.current)
// self.scroll2bottom()
}
else if (event.which === 40) {
if (_cmdIndex > -1) {
setCmdIndex(prevState => prevState--)
}
inputEl.current.innerText = _cmdIndex >= 0 ? _cmdHistory[_cmdIndex] : _cmdTemp
inputEl.current.focus()
// putCursor2End(inputEl.current)
// self.scroll2bottom()
} else {
setCmdTemp(inputEl.current.innerText)
}
console.log({ _cmdHistory })
console.log({ _cmdIndex })
console.log({ _cmdTemp })
}
const moveGhostbar = (event) => {
return props.api.getPosition(event) + 'px'
}
const removeGhostbar = (event) => {
if (toggleDownUp === 'fa-angle-double-up') {
console.log('remove event')
setToggleDownUp('fa-angle-double-down')
}
props.event.trigger('resize', [props.api.getPostion(event)])
}
const mousedown = (event) => {
console.log({ windowHeight })
console.log(event.which === 1, 'event.which === 1')
event.preventDefault()
moveGhostbar(event)
if (event.which === 1) {
console.log('event .which code 1')
moveGhostbar(event)
}
}
const cancelGhostbar = (event) => {
if (event.keyCode === 27) {
console.log('event .key code 27')
}
}
return (
<div>
<div className="bar">
<div style={{ height: '323px' }} className='panel_2A0YE0'>
<div className="bar_2A0YE0">
{/* ${self._view.dragbar} */}
<div className="dragbarHorizontal"></div>
<div className="menu border-top border-dark bg-light" data-id="terminalToggleMenu">
<div className="dragbarHorizontal_2A0YE0" onMouseDown={mousedown}></div>
<div className="menu_2A0YE0 border-top border-dark bg-light" data-id="terminalToggleMenu">
{/* ${self._view.icon} */}
<i className={`mx-2 toggleTerminal fas ${toggleDownUp}`} data-id="terminalToggleIcon" onClick={ handleMinimizeTerminal }></i>
<i className={`mx-2 toggleTerminal_2A0YE0 fas ${toggleDownUp}`} data-id="terminalToggleIcon" onClick={ handleMinimizeTerminal }></i>
<div className="mx-2" id="clearConsole" data-id="terminalClearConsole" >
<i className="fas fa-ban" aria-hidden="true" title="Clear console"
></i>
</div>
{/* ${self._view.pendingTxCount} */}
<div className="mx-2" title='Pending Transactions'>0</div>
<div className="verticalLine"></div>
<div className="pt-1 h-80 mx-3 align-items-center listenOnNetwork custom-control custom-checkbox">
<div className="verticalLine_2A0YE0"></div>
<div className="pt-1 h-80 mx-3 align-items-center listenOnNetwork_2A0YE0 custom-control custom-checkbox">
<input
className="custom-control-input"
id="listenNetworkCheck"
@ -194,13 +383,13 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
listen on network
</label>
</div>
<div className="search">
<i className="fas fa-search searchIcon bg-light" aria-hidden="true"></i>
<div className="search_2A0YE0">
<i className="fas fa-search searchIcon_2A0YE0 bg-light" aria-hidden="true"></i>
{/* ${self._view.inputSearch} */}
<input
// spellcheck = "false"
type="text"
className="border filter form-control"
className="border filter_2A0YE0 form-control"
id="searchInput"
// onkeydown=${filter}
placeholder="Search with transaction hash or address"
@ -208,7 +397,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
</div>
</div>
</div>
<div className="terminal_container" data-id="terminalContainer" >
<div tabIndex={-1} className="terminal_container_2A0YE0" data-id="terminalContainer" >
{/* onScroll=${throttle(reattach, 10)} onkeydown=${focusinput} */}
{/* {props.autoCompletePopup.render()} */}
{console.log({ props })}
@ -219,8 +408,15 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
opacity: '0.1',
zIndex: -1
}}></div>
<div className="terminal">
<div id="journal" className="journal" data-id="terminalJournal">
<div className="terminal_2A0YE0">
<div id="journal" className="journal_2A0YE0" data-id="terminalJournal">
<div className="px-4 block_2A0YE0" data-id="block_null">
{Object.entries(state.journalBlocks).map((x, index) => (
<div key={index}>
{x}
</div>
))}
</div>
<div className="anchor">
{/* ${background} */}
<div className="overlay background"></div>
@ -228,9 +424,9 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
<div className="overlay text"></div>
</div>
</div>
<div id="terminalCli" data-id="terminalCli" className="cli" onClick={focusinput}>
<div id="terminalCli" data-id="terminalCli" className="cli_2A0YE0" onClick={focusinput}>
<span className="prompt">{'>'}</span>
<span className="input" ref={inputEl} spellCheck="false" contentEditable="true" id="terminalCliInput" data-id="terminalCliInput" onPaste={handlePaste}></span>
<span className="input" ref={inputEl} spellCheck="false" contentEditable="true" id="terminalCliInput" data-id="terminalCliInput" onPaste={handlePaste} onKeyDown={ handleKeyDown }></span>
</div>
</div>
</div>

19
package-lock.json generated

@ -10656,6 +10656,15 @@
"tweetnacl": "^0.14.3"
}
},
"beautiful-react-hooks": {
"version": "0.35.0",
"resolved": "https://registry.npmjs.org/beautiful-react-hooks/-/beautiful-react-hooks-0.35.0.tgz",
"integrity": "sha512-EDjpQWskuK7ob+rfH/Xt6UpFA+vC+ARM1TYAWRgYWcjcaDCGFuc3q5Ko4WJQUcFP2cq9ps3GihUSqN+KfUwQdg==",
"requires": {
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1"
}
},
"bech32": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
@ -24291,6 +24300,11 @@
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
},
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
"lodash.defaultsdeep": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz",
@ -24392,6 +24406,11 @@
"lodash._reinterpolate": "^3.0.0"
}
},
"lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
},
"lodash.toarray": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",

@ -89,7 +89,7 @@
"onchange": "onchange apps/remix-ide/build/app.js -- npm-run-all lint",
"remixd": "nx build remixd && nx serve remixd --folder=./apps/remix-ide/contracts --remixide=http://127.0.0.1:8080",
"selenium": "selenium-standalone start",
"selenium-install": "selenium-standalone install",
"selenium-install": "selenium-standalone install",
"sourcemap": "exorcist --root ../ apps/remix-ide/build/app.js.map > apps/remix-ide/build/app.js",
"test-browser": "npm-run-all -lpr selenium make-mock-compiler serve browsertest",
"watch": "watchify apps/remix-ide/src/index.js -dv -p browserify-reload -o apps/remix-ide/build/app.js --exclude solc",
@ -146,6 +146,7 @@
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"axios": ">=0.21.1",
"beautiful-react-hooks": "^0.35.0",
"brace": "^0.8.0",
"change-case": "^4.1.1",
"chokidar": "^2.1.8",

Loading…
Cancel
Save