Skip to content

Commit 5c32306

Browse files
authored
Merge pull request #6306 from ethereum/fix-bottom-bar
fix bottom bar
2 parents 2a5985f + a9b45cf commit 5c32306

File tree

9 files changed

+149
-50
lines changed

9 files changed

+149
-50
lines changed

apps/remix-ide/src/app.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ import Editor from './app/editor/editor'
110110
import Terminal from './app/panels/terminal'
111111
import TabProxy from './app/panels/tab-proxy.js'
112112
import { Plugin } from '@remixproject/engine'
113+
import BottomBarPanel from './app/components/bottom-bar-panel'
113114

114115
const _paq = (window._paq = window._paq || [])
115116

@@ -526,7 +527,9 @@ class AppComponent {
526527
const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport)
527528
this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor)//, appManager)
528529

529-
this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, this.statusBar, this.topBar, filePanel, pluginManagerComponent, this.settings, this.pinnedPanel, this.popupPanel])
530+
const bottomBarPanel = new BottomBarPanel()
531+
532+
this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, this.statusBar, this.topBar, filePanel, pluginManagerComponent, this.settings, this.pinnedPanel, this.popupPanel, bottomBarPanel])
530533

531534
// CONTENT VIEWS & DEFAULT PLUGINS
532535
const openZeppelinProxy = new OpenZeppelinProxy(blockchain)
@@ -573,6 +576,7 @@ class AppComponent {
573576
tabs: { plugin: tabProxy, active: true },
574577
editor: { plugin: editor, active: true },
575578
main: { plugin: appPanel, active: false },
579+
bottomBar: { plugin: bottomBarPanel, active: true },
576580
terminal: { plugin: terminal, active: true, minimized: false }
577581
}
578582
}
@@ -607,6 +611,7 @@ class AppComponent {
607611
await this.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
608612
await this.appManager.activatePlugin(['topbar'])
609613
await this.appManager.activatePlugin(['statusBar'])
614+
await this.appManager.activatePlugin(['bottomBar'])
610615
await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
611616
await this.appManager.activatePlugin(['pinnedPanel'])
612617
await this.appManager.activatePlugin(['popupPanel'])
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react'
2+
import { Plugin } from '@remixproject/engine'
3+
import { PluginViewWrapper } from '@remix-ui/helper'
4+
import * as packageJson from '../../../../../package.json'
5+
import BottomBar from './bottom-bar'
6+
7+
const profile = {
8+
displayName: 'Bottom Bar',
9+
name: 'bottomBar',
10+
methods: [],
11+
events: [],
12+
description: 'Editor bottom bar (renders above dragbar-terminal)',
13+
version: packageJson.version,
14+
kind: 'system'
15+
}
16+
17+
export default class BottomBarPanel extends Plugin {
18+
private dispatch: ((state: any) => void) | null = null
19+
20+
constructor() {
21+
super(profile)
22+
}
23+
24+
setDispatch = (dispatch) => {
25+
this.dispatch = dispatch
26+
}
27+
28+
onActivation() {
29+
this.renderComponent()
30+
}
31+
32+
render() {
33+
return (
34+
<div className="panel" data-id="bottomBarPanelView">
35+
<PluginViewWrapper plugin={this} />
36+
</div>
37+
)
38+
}
39+
40+
updateComponent() {
41+
return <BottomBar plugin={this} />
42+
}
43+
44+
renderComponent() {
45+
this.dispatch && this.dispatch({})
46+
}
47+
}

apps/remix-ide/src/app/components/bottom-bar.tsx

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ interface BottomBarProps {
66
plugin: Plugin
77
}
88

9+
const SUPPORTED_EXTENSIONS = ['sol', 'vy', 'circom', 'js', 'ts']
10+
911
export const BottomBar = ({ plugin }: BottomBarProps) => {
1012
const [explaining, setExplaining] = useState(false)
1113
const [aiSwitch, setAiSwitch] = useState(true)
@@ -22,48 +24,52 @@ export const BottomBar = ({ plugin }: BottomBarProps) => {
2224
}
2325
}
2426

25-
const getCurrentExt = async () => {
26-
try {
27-
const path = await plugin.call('fileManager', 'getCurrentFile')
28-
setCurrentFilePath(path)
29-
const ext = path?.split('.').pop()?.toLowerCase() || ''
30-
setCurrentExt(ext)
31-
} catch (err) {
32-
console.info('No current file selected.')
33-
setCurrentFilePath('')
34-
setCurrentExt('')
35-
}
27+
const handleExtChange = (ext: string) => {
28+
setCurrentExt(ext || '')
29+
}
30+
31+
const handleFileChange = (path: string) => {
32+
setCurrentFilePath(path || '')
3633
}
3734

3835
getAI()
39-
getCurrentExt()
4036

41-
plugin.on('settings', 'copilotChoiceUpdated', (isChecked) => {
42-
setAiSwitch(isChecked)
43-
})
37+
const onCopilot = (isChecked: boolean) => setAiSwitch(!!isChecked)
4438

45-
plugin.on('fileManager', 'currentFileChanged', getCurrentExt)
39+
plugin.on('tabs', 'extChanged', handleExtChange)
40+
41+
plugin.on('settings', 'copilotChoiceUpdated', onCopilot)
42+
plugin.on('fileManager', 'currentFileChanged', handleFileChange)
43+
44+
plugin.call('fileManager', 'getCurrentFile').then(path => {
45+
handleFileChange(path)
46+
const ext = path?.split('.').pop()?.toLowerCase() || ''
47+
handleExtChange(ext)
48+
}).catch(() => {
49+
handleFileChange('')
50+
handleExtChange('')
51+
})
4652

4753
return () => {
54+
plugin.off('tabs', 'extChanged')
4855
plugin.off('fileManager', 'currentFileChanged')
56+
plugin.off('settings', 'copilotChoiceUpdated')
4957
}
50-
5158
}, [plugin])
5259

5360
const handleExplain = async () => {
5461
if (!currentFilePath) {
55-
plugin.call('notification', 'toast', 'No file selected to explain.');
62+
plugin.call('notification', 'toast', 'No file selected to explain.')
5663
return
5764
}
5865
setExplaining(true)
5966
try {
6067
await plugin.call('menuicons', 'select', 'remixaiassistant')
61-
await new Promise(resolve => setTimeout(resolve, 500))
68+
await new Promise((resolve) => setTimeout(resolve, 500))
6269
const content = await plugin.call('fileManager', 'readFile', currentFilePath)
6370
await plugin.call('remixAI', 'chatPipe', 'code_explaining', content + "\n\nExplain briefly the snipped above!")
64-
6571
} catch (err) {
66-
console.error("Explain failed:", err)
72+
console.error('Explain failed:', err)
6773
}
6874
setExplaining(false)
6975
}
@@ -83,22 +89,25 @@ export const BottomBar = ({ plugin }: BottomBarProps) => {
8389
return ''
8490
}
8591

92+
if (!SUPPORTED_EXTENSIONS.includes(currentExt)) {
93+
return null
94+
}
95+
8696
return (
87-
<div className="bottom-bar border-top border-bottom">
88-
{getExplainLabel() && (
89-
<button
90-
className="btn btn-ai"
91-
onClick={handleExplain}
92-
disabled={explaining || !currentFilePath}
93-
>
94-
<img src="assets/img/remixAI_small.svg" alt="Remix AI" className="explain-icon" />
95-
<span>{getExplainLabel()}</span>
96-
</button>
97-
)}
97+
<div className="bottom-bar border-top border-bottom" data-id="bottomBarPanel">
98+
<button
99+
className="btn btn-ai"
100+
onClick={handleExplain}
101+
disabled={explaining || !currentFilePath}
102+
data-id="bottomBarExplainBtn"
103+
>
104+
<img src="assets/img/remixAI_small.svg" alt="Remix AI" className="explain-icon" />
105+
<span>{getExplainLabel()}</span>
106+
</button>
98107
<div className="copilot-toggle">
99-
<span className={aiSwitch ? "on" : ""}>AI copilot</span>
100-
<label className="switch" data-id="copilot_toggle" >
101-
<input type="checkbox" checked={aiSwitch} onChange={toggleAI}/>
108+
<span className={aiSwitch ? 'on' : ''}>AI copilot</span>
109+
<label className="switch" data-id="copilot_toggle">
110+
<input type="checkbox" checked={aiSwitch} onChange={toggleAI} />
102111
<span className="slider"></span>
103112
</label>
104113
</div>
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
.bottom-bar {
22
display: flex;
3+
flex: 0 0 auto;
34
align-items: center;
45
padding: 4px 16px;
56
background-color: var(--bs-light) !important;
67
height: 32px;
8+
position: sticky;
9+
top: 0;
10+
z-index: 10;
711
}
812

9-
.explain-icon {
13+
.bottom-bar .explain-icon {
1014
width: 12px;
1115
height: 12px;
1216
}
1317

14-
.copilot-toggle {
18+
.bottom-bar .copilot-toggle {
1519
margin-left: auto;
1620
display: flex;
1721
align-items: center;
@@ -22,32 +26,32 @@
2226
line-height: 1;
2327
}
2428

25-
.copilot-toggle span {
29+
.bottom-bar .copilot-toggle span {
2630
font-family: 'Nunito Sans', sans-serif;
2731
font-size: 12px;
2832
font-weight: 700;
2933
color: var(--text-muted);
3034
transition: color 0.3s;
3135
}
3236

33-
.copilot-toggle span.on {
37+
.bottom-bar .copilot-toggle span.on {
3438
color: var(--text-bright);
3539
}
3640

37-
.switch {
41+
.bottom-bar .switch {
3842
position: relative;
3943
display: inline-block;
4044
width: 18px;
4145
height: 10px;
4246
}
4347

44-
.switch input {
48+
.bottom-bar .switch input {
4549
opacity: 0;
4650
width: 0;
4751
height: 0;
4852
}
4953

50-
.slider {
54+
.bottom-bar .slider {
5155
position: absolute;
5256
cursor: pointer;
5357
top: 0; left: 0; right: 0; bottom: 0;
@@ -57,7 +61,7 @@
5761
padding: 1px;
5862
}
5963

60-
.slider:before {
64+
.bottom-bar .slider:before {
6165
position: absolute;
6266
content: "";
6367
height: 8px;
@@ -69,10 +73,10 @@
6973
border-radius: 50%;
7074
}
7175

72-
.switch input:checked + .slider {
76+
.bottom-bar .switch input:checked + .slider {
7377
background-color: var(--custom-ai-color);
7478
}
7579

76-
.switch input:checked + .slider:before {
80+
.bottom-bar .switch input:checked + .slider:before {
7781
transform: translateX(8px);
7882
}

apps/remix-ide/src/app/panels/layout.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface panels {
1818
tabs: panelState
1919
editor: panelState
2020
main: panelState
21+
bottomBar: panelState
2122
terminal: panelState
2223
}
2324

apps/remix-ide/src/app/panels/terminal.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import EventManager from '../../lib/events'
1010

1111
import { CompilerImports } from '@remix-project/core-plugin' // eslint-disable-line
1212
import { RemixUiXterminals } from '@remix-ui/xterm'
13-
import { BottomBar } from '../components/bottom-bar'
1413

1514
const KONSOLES = []
1615

@@ -143,7 +142,6 @@ export default class Terminal extends Plugin {
143142
updateComponent(state) {
144143
return (
145144
<>
146-
<BottomBar plugin={this} />
147145
<RemixUITerminalWrapper
148146
plugin={state.plugin}
149147
onReady={state.onReady}

apps/remix-ide/src/remixAppManager.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ let requiredModules = [
3535
'menuicons',
3636
'filePanel',
3737
'terminal',
38+
'bottomBar',
3839
'statusBar',
3940
'settings',
4041
'pluginManager',

libs/remix-ui/panel/src/lib/main/main-panel.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const RemixUIMainPanel = (props: RemixUIMainPanelProps) => {
1818
const mainPanelRef = useRef<HTMLDivElement>(null)
1919
const tabsRef = useRef<HTMLDivElement>(null)
2020
const terminalRef = useRef<HTMLDivElement>(null)
21+
const bottomBarRef = useRef<HTMLDivElement>(null)
2122

2223
const refs = [tabsRef, editorRef, mainPanelRef, terminalRef]
2324

@@ -56,18 +57,47 @@ const RemixUIMainPanel = (props: RemixUIMainPanelProps) => {
5657
}
5758

5859
const resize = (height: number) => {
60+
syncBottomBarPosition()
5961
layout.emit('resize', height)
6062
}
6163

64+
const syncBottomBarPosition = () => {
65+
if (terminalRef.current && bottomBarRef.current && mainPanelRef.current && !layout.panels.terminal.minimized) {
66+
const bottomBarElement = bottomBarRef.current
67+
const terminalElement = terminalRef.current
68+
const mainPanelElement = mainPanelRef.current
69+
70+
const bottomBarHeight = bottomBarElement.offsetHeight;
71+
72+
if (editorRef.current) {
73+
const dragBarHeight = 8
74+
const newEditorHeight = mainPanelElement.offsetHeight - terminalElement.offsetHeight - bottomBarHeight - dragBarHeight
75+
editorRef.current.style.height = `${newEditorHeight}px`
76+
}
77+
} else if (bottomBarRef.current) {
78+
bottomBarRef.current.style.visibility = 'hidden'
79+
if (editorRef.current && mainPanelRef.current && bottomBarRef.current) {
80+
editorRef.current.style.height = `${mainPanelRef.current.offsetHeight - bottomBarRef.current.offsetHeight}px`
81+
}
82+
}
83+
}
84+
6285
return (
63-
<div className="mainview">
86+
<div className="mainview" ref={mainPanelRef}>
6487
{Object.values(plugins).map((pluginRecord, i) => {
88+
let panelRef = refs[i]
89+
if (pluginRecord.profile.name === 'terminal') {
90+
panelRef = terminalRef
91+
} else if (pluginRecord.profile.name === 'bottomBar') {
92+
panelRef = bottomBarRef
93+
}
94+
6595
return (
6696
<React.Fragment key={`mainView${i}`}>
6797
{pluginRecord.profile.name === 'terminal' ? (
6898
<DragBar key="dragbar-terminal" onResize={resize} hidden={pluginRecord.minimized || false} setHideStatus={showTerminal} refObject={terminalRef}></DragBar>
6999
) : null}
70-
<RemixUIPanelPlugin ref={refs[i]} key={pluginRecord.profile.name} pluginRecord={pluginRecord} />
100+
<RemixUIPanelPlugin ref={panelRef} key={pluginRecord.profile.name} pluginRecord={pluginRecord} />
71101
</React.Fragment>
72102
)
73103
})}

libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ export const TabsUI = (props: TabsUIProps) => {
173173
const activateTab = (name: string) => {
174174
const index = tabs.current.findIndex((tab) => tab.name === name)
175175
currentIndexRef.current = index
176+
const ext = getExt(name)
177+
props.plugin.emit('extChanged', ext)
176178
dispatch({ type: 'SELECT_INDEX', payload: index, ext: getExt(name) })
177179
}
178180

@@ -582,6 +584,8 @@ export const TabsUI = (props: TabsUIProps) => {
582584
onSelect={(index) => {
583585
props.onSelect(index)
584586
currentIndexRef.current = index
587+
const ext = getExt(props.tabs[currentIndexRef.current].name)
588+
props.plugin.emit('extChanged', ext)
585589
dispatch({
586590
type: 'SELECT_INDEX',
587591
payload: index,

0 commit comments

Comments
 (0)