Skip to content

panel sidebar #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/IDE/IdeEnvironment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

const IdeEnvironment = () => {
return {
editors: {}
}
}
export default IdeEnvironment
7 changes: 7 additions & 0 deletions app/IDE/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// This is the access point to the API that Coding WebIDE exposes
// Idea taken from atom, this is the equivalence of `window.atom`
//
// see: https://github.com/atom/atom/blob/master/src/atom-environment.coffee

import IdeEnvironment from './IdeEnvironment'
export default window.ide = IdeEnvironment()
4 changes: 2 additions & 2 deletions app/commands/commandBindings/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ export default {


'file:save': (c) => {
const TabState = getState().TabState
const { TabState } = getState()
const activeTab = Tab.selectors.getActiveTab(TabState)
const content = activeTab.editor.getValue()
const content = activeTab ? ide.editors[activeTab.id].getValue() : ''

if (!activeTab.path) {
const createFile = createFileWithContent(content)
Expand Down
37 changes: 35 additions & 2 deletions app/components/Bar/SideBar.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
/* @flow weak */
import { connect } from 'react-redux'
import cx from 'classnames'
import { activateExtenstion } from '../Package/actions'

export default ({ side }) => {
const SideBarLabel = ({ label, isActive, onClick }) => {
return (
<div className={cx('side-bar-label', {
active: isActive
})} onClick={onClick} >
<div className='side-bar-label-container'>
<div className='side-bar-label-content'>
<i className={cx('icon', label.icon)}></i>
<span>{label.text}</span>
</div>
</div>
</div>
)
}

const _SideBar = ({ labels, side, activeExtenstionId, dispatch }) => {
return (
<div className={'bar side-bar ' + side}>
this is side bar
{labels.map((label, idx) =>
<SideBarLabel key={label.packageId}
label={label}
onClick={e => dispatch(activateExtenstion(label.packageId))}
isActive={activeExtenstionId === label.packageId}
/>
)}
</div>
)
}

export default connect((state, { side }) => {
const localPackages = state.PackageState.localPackages
const { extensionIds, activeExtenstionId } = state.PackageState.extensionsUIState.panels[side]
const labels = extensionIds.map(id => {
let label = localPackages[id].ui.label
return {...label, packageId: id}
})
return { labels, activeExtenstionId }
})(_SideBar)
12 changes: 11 additions & 1 deletion app/components/CodeMirrorEditor/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,20 @@ class CodeMirrorEditor extends Component {
autoCloseBrackets: true,
});

// @fixme:
// related counterparts:
// 1. IdeEnvironment.js
// 2. commandBindings/file.js
window.ide.editors[tab.id] = editor

// 1. resize
editor.setSize(width, height);

// 2. prevent default codemirror dragover handler, so the drag-to-split feature can work
// but the default handler that open a file on drop is actually pretty neat,
// should make our drag feature compatible with it later
editor.on('dragover', e => e.preventDefault())

if (tab.content) {
const {body, path} = tab.content;
const modeInfo = this.getMode(path);
Expand All @@ -44,7 +55,6 @@ class CodeMirrorEditor extends Component {
}
editor.focus();
editor.isFocused = editor.hasFocus; // little hack to make codemirror work with legacy interface
tab.editor = editor;
editor.on('change', this.onChange);
editor.on('focus', () => this.props.dispatch(TabActions.activateTab(tab.id)))
}
Expand Down
1 change: 0 additions & 1 deletion app/components/FileTree/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class FileTree extends Component {

componentDidMount () {
subscribeToFileChange()
this.props.initializeFileTree()
}

onContextMenu = (e, node) => {
Expand Down
3 changes: 2 additions & 1 deletion app/components/FileTree/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ const findNodeByPath = (path) => {

var _state = {}
_state.rootNode = RootNode

const normalizeState = (_state) => {
var state = {
findNodeByPath,
Expand All @@ -206,6 +205,8 @@ const normalizeState = (_state) => {
return state
}

_state = normalizeState(_state)

export default handleActions({
[FILETREE_LOAD_DATA]: (state, action) => {
let {node, data} = action.payload
Expand Down
38 changes: 0 additions & 38 deletions app/components/Package/ExtensionPanelContent.js

This file was deleted.

22 changes: 12 additions & 10 deletions app/components/Package/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ export const fetchPackageList = () => dispatch => {
export const PACKAGE_UPDATE_LOCAL = 'PACKAGE_UPDATE_LOCAL'
export const updateLocalPackage = createAction(PACKAGE_UPDATE_LOCAL)

export const fetchPackage = (pkgName) => (dispatch, getState) => {
const pkgInfo = api.fetchPackageInfo(pkgName)
const pkgScript = api.fetchPackageScript(pkgName)
export const PACKAGE_TOGGLE = 'PACKAGE_TOGGLE'
export const togglePackage = createAction(PACKAGE_TOGGLE, (pkgId, shouldEnable) => ({
id: pkgId,
shouldEnable: shouldEnable
}))

export const fetchPackage = (pkgId) => (dispatch, getState) => {
const pkgInfo = api.fetchPackageInfo(pkgId)
const pkgScript = api.fetchPackageScript(pkgId)
.then(script => {
let storageKey = `CodingPackage___${pkgName}`
let storageKey = `CodingPackage___${pkgId}`
localStorage.setItem(storageKey, script)
return storageKey
})
Expand All @@ -26,9 +32,5 @@ export const fetchPackage = (pkgName) => (dispatch, getState) => {
})
}


export const PACKAGE_TOGGLE = 'PACKAGE_TOGGLE'
export const togglePackage = createAction(PACKAGE_TOGGLE, (pkgName, shouldEnable) => ({
name: pkgName,
enable: shouldEnable
}))
export const PACKAGE_ACTIVATE_EXTENSION = 'PACKAGE_ACTIVATE_EXTENSION'
export const activateExtenstion = createAction(PACKAGE_ACTIVATE_EXTENSION)
2 changes: 1 addition & 1 deletion app/components/Package/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/* @flow weak */
export PackageControlView from './PackageControlView'
export ExtensionPanelContent from './ExtensionPanelContent'
136 changes: 125 additions & 11 deletions app/components/Package/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,47 @@ import { update } from '../../utils'
import {
updatePackageList,
updateLocalPackage,
togglePackage
togglePackage,
activateExtenstion,
} from './actions'

const defaultState = {
remotePackages: {},
localPackages: {}
localPackages: {},
extensionsUIState: {
panels: {
right: {
extensionIds: [],
activeExtenstionId: '',
},
left: {
extensionIds: [],
activeExtenstionId: '',
},
bottom: {
extensionIds: [],
activeExtenstionId: '',
}
},
},
}

const toggleExtensionAvailability = (state, pkgId) => {
// handle availability state of extension packages in side panels
let pkg = state.localPackages[pkgId]
if (!pkg.type === 'extension' || !pkg.ui || !pkg.ui.position) return state

let extensionIds = state.extensionsUIState.panels[pkg.ui.position].extensionIds
if (extensionIds.includes(pkgId) === pkg.enabled) return state

return update(state, {
extensionsUIState: { panels: { [pkg.ui.position]: {
extensionIds: pkg.enabled
? {'$push' : [pkgId] }
: {'$without': pkgId }
}}}
})

}

export default handleActions({
Expand All @@ -18,23 +53,102 @@ export default handleActions({

[updateLocalPackage]: (state, action) => {
const packageObj = action.payload
updateLocalPackage(packageObj)
return update(state, {
let nextState = update(state, {
localPackages: {
[packageObj.name]: { $set: packageObj }
[packageObj.id]: { $set: packageObj }
}
})
return toggleExtensionAvailability(nextState, packageObj.id)
},

[togglePackage]: (state, action) => {
let { name, enable } = action.payload
let targetPackage = state.localPackages[name]
if (enable === targetPackage.enabled) return state
if (typeof enable !== 'boolean') enable = !targetPackage.enabled
return update(state, {
let { id, shouldEnable } = action.payload
let targetPackage = state.localPackages[id]
if (shouldEnable === targetPackage.enabled) return state
if (typeof shouldEnable !== 'boolean') shouldEnable = !targetPackage.enabled

let nextState = update(state, {
localPackages: {
[name]: { enabled: { $set: enable } }
[id]: { enabled: { $set: shouldEnable } }
}
})

return toggleExtensionAvailability(nextState, id)
}

}, defaultState)


const getPanelByRef = (PanelState, ref) => {
return PanelState.panels[PanelState.panelRefs[ref]]
}
export const PackageCrossReducer = handleActions({
[activateExtenstion]: (allState, action) => {
let nextState = allState
let packageId = action.payload

const { PackageState, PanelState } = allState
const pkg = PackageState.localPackages[packageId]
const panelSide = pkg.ui.position

const activeExtenstionId = PackageState.extensionsUIState.panels[panelSide].activeExtenstionId
const targetPanel = getPanelByRef(PanelState, `PANEL_${panelSide.toUpperCase()}`)

if (activeExtenstionId === packageId) packageId = ''
const shouldHidePanel = packageId ? false : true
nextState = update(nextState, {
PanelState: {
panels: {
[targetPanel.id]: { hide: { $set: shouldHidePanel } }
}
}
})

// special case: redistribute size between center and right panel
if (targetPanel.ref === 'PANEL_RIGHT') {
let centerPanel = getPanelByRef(nextState.PanelState, 'PANEL_CENTER')
let centerPanelSize = shouldHidePanel
? centerPanel.size + targetPanel.size
: centerPanel.size - targetPanel.size
if (centerPanelSize <= 0) centerPanelSize = targetPanel.size

nextState = update(nextState, {
PanelState: {
panels: {
[centerPanel.id]: {
size: { $set: centerPanelSize }
}
}
}
})
}

return update(nextState, {
PackageState: {
extensionsUIState: { panels: {[panelSide]: {
activeExtenstionId: { $set: packageId }
}}}
}
})
}
})

/*
Example package manifest:

{
id: "coding-ide-env",
version: "0.0.1",
description: "Extension for Coding WebIDE, manage IDE environment",
main: "index.js",
type: "extension",
ui: {
position: "right",
label: {
text: "Environment",
icon: "fa fa-close"
}
}
}

*/
Loading