Mise en place base Redux
This commit is contained in:
parent
411894586b
commit
324c267f8a
|
@ -122,7 +122,7 @@ html, body {
|
|||
|
||||
}
|
||||
|
||||
.edit img.desktop-app-icon {
|
||||
.edit .desktop-app > .app-icon {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
display: inline-block;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
var Util = require('../util');
|
||||
var path = require('path');
|
||||
|
||||
// Action types
|
||||
var LOAD_DESKTOP_APPS = exports.LOAD_PROFILE = 'LOAD_DESKTOP_APPS';
|
||||
var LOAD_DESKTOP_APPS_SUCCESS = exports.LOAD_DESKTOP_APPS_SUCCESS = 'LOAD_DESKTOP_APPS_SUCCESS';
|
||||
var LOAD_DESKTOP_APPS_FAILED = exports.LOAD_DESKTOP_APPS_FAILED = 'LOAD_DESKTOP_APPS_FAILED';
|
||||
|
||||
// Actions creator
|
||||
exports.loadDesktopApps = function() {
|
||||
return function(dispatch, getState) {
|
||||
|
||||
var baseDirs = global.process.env.XDG_DATA_DIRS.split(':').map(function(baseDir){
|
||||
return path.join(baseDir, 'applications');
|
||||
});
|
||||
|
||||
dispatch({ type: LOAD_DESKTOP_APPS });
|
||||
|
||||
return Util.DesktopApps.loadAllDesktopFiles(baseDirs)
|
||||
.then(function(desktopApps) {
|
||||
dispatch({ type: LOAD_DESKTOP_APPS_SUCCESS, desktopApps: desktopApps });
|
||||
})
|
||||
.catch(function(err) {
|
||||
dispatch({ type: LOAD_DESKTOP_APPS_FAILED, error: err });
|
||||
})
|
||||
;
|
||||
|
||||
};
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
exports.mauncher = require('./launcher');
|
||||
exports.edit = require('./edit');
|
|
@ -0,0 +1,23 @@
|
|||
var Util = require('../util');
|
||||
|
||||
var LOAD_PROFILE = exports.LOAD_PROFILE = 'LOAD_PROFILE';
|
||||
var LOAD_PROFILE_SUCCESS = exports.LOAD_PROFILE_SUCCESS = 'LOAD_PROFILE_SUCCESS';
|
||||
var LOAD_PROFILE_FAILED = exports.LOAD_PROFILE_FAILED = 'LOAD_PROFILE_FAILED';
|
||||
|
||||
exports.loadProfile = function(profilePath) {
|
||||
|
||||
return function(dispatch, getState) {
|
||||
|
||||
dispatch({ type: LOAD_PROFILE });
|
||||
|
||||
return Util.System.loadJSONFile(profilePath)
|
||||
.then(function(profile) {
|
||||
dispatch({ type: LOAD_PROFILE_SUCCESS, profile: profile });
|
||||
})
|
||||
.catch(function(err) {
|
||||
dispatch({ type: LOAD_PROFILE_FAILED, error: err });
|
||||
})
|
||||
;
|
||||
|
||||
};
|
||||
};
|
11
js/app.jsx
11
js/app.jsx
|
@ -3,12 +3,13 @@ var minimist = require('minimist');
|
|||
var gui = global.window.require('nw.gui');
|
||||
var LauncherView = require('./components/launcher-view.jsx');
|
||||
var EditView = require('./components/edit-view.jsx');
|
||||
var Provider = require('react-redux').Provider;
|
||||
var stores = require('./stores');
|
||||
|
||||
// Internal constants
|
||||
var DEFAULT_PROFILE = './default-profile.json';
|
||||
var PROCESS_OPTS = minimist(gui.App.argv);
|
||||
|
||||
|
||||
// Main component
|
||||
var App = React.createClass({
|
||||
|
||||
|
@ -22,8 +23,12 @@ var App = React.createClass({
|
|||
render: function() {
|
||||
|
||||
var view = this.state.editMode ?
|
||||
<EditView profilePath={this.state.profilePath} /> :
|
||||
<LauncherView profilePath={this.state.profilePath ? this.state.profilePath : DEFAULT_PROFILE } />
|
||||
<Provider store={stores.editStore}>
|
||||
{ function() { return <EditView profilePath={this.state.profilePath} />; }.bind(this) }
|
||||
</Provider> :
|
||||
<Provider store={stores.launcherStore}>
|
||||
{ function() { return <LauncherView profilePath={this.state.profilePath ? this.state.profilePath : DEFAULT_PROFILE } />; }.bind(this) }
|
||||
</Provider>
|
||||
;
|
||||
|
||||
return (
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
var React = require('react');
|
||||
var Util = require('../util');
|
||||
var LazyLoad = require('./mixins/lazy-load');
|
||||
|
||||
var LOADING_ICON = 'img/hourglass.svg';
|
||||
var DEFAULT_ICON = 'img/default-icon.svg';
|
||||
|
||||
module.exports = React.createClass({
|
||||
|
||||
mixins: [LazyLoad],
|
||||
|
||||
getInitialState: function() {
|
||||
return { icon: DEFAULT_ICON, currentTheme: undefined };
|
||||
},
|
||||
|
||||
onInViewport: function() {
|
||||
this.updateIconIfInViewport();
|
||||
},
|
||||
|
||||
updateIconIfInViewport: function() {
|
||||
|
||||
var currentTheme = this.state.currentTheme;
|
||||
var newTheme = this.props.theme;
|
||||
|
||||
if( !this.isInViewport() || newTheme === currentTheme ) return;
|
||||
|
||||
this.setState({ icon: LOADING_ICON, currentTheme: newTheme });
|
||||
|
||||
var desktopEntry = this.props.desktopEntry;
|
||||
|
||||
this._findIcon(this.props.icon, newTheme);
|
||||
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
this.updateIconIfInViewport();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var icon = this.state.icon;
|
||||
|
||||
return (
|
||||
<img src={icon} className="app-icon" />
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
_findIcon: function(iconPath, theme) {
|
||||
|
||||
var self = this;
|
||||
|
||||
console.log('Search icon %s:%s', iconPath, theme);
|
||||
|
||||
Util.DesktopApps.findIcon(iconPath || DEFAULT_ICON, theme)
|
||||
.then(function(iconPath) {
|
||||
if( !iconPath || /\.xpm$/.test(iconPath) ) {
|
||||
return Util.DesktopApps.findIcon(DEFAULT_ICON, theme);
|
||||
}
|
||||
return iconPath;
|
||||
})
|
||||
.then(function(iconPath) {
|
||||
global.window.requestAnimationFrame(function() {
|
||||
self.setState({ icon: iconPath });
|
||||
});
|
||||
})
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
});
|
|
@ -1,76 +1,23 @@
|
|||
var React = require('react');
|
||||
var Util = require('../util');
|
||||
var LazyLoad = require('./mixins/lazy-load');
|
||||
|
||||
var LOADING_ICON = 'img/hourglass.svg';
|
||||
var DEFAULT_ICON = 'img/default-icon.svg';
|
||||
var AppIcon = require('./app-icon.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
|
||||
mixins: [LazyLoad],
|
||||
|
||||
getInitialState: function() {
|
||||
return { icon: LOADING_ICON, currentTheme: undefined };
|
||||
},
|
||||
|
||||
onInViewport: function() {
|
||||
this.updateIconIfInViewport();
|
||||
},
|
||||
|
||||
updateIconIfInViewport: function() {
|
||||
|
||||
var currentTheme = this.state.currentTheme;
|
||||
var newTheme = this.props.theme;
|
||||
|
||||
if( !this.isInViewport() || newTheme === currentTheme ) return;
|
||||
|
||||
this.setState({ icon: LOADING_ICON, currentTheme: newTheme });
|
||||
|
||||
var desktopEntry = this.props.desktopEntry;
|
||||
|
||||
this._findIcon(desktopEntry.Icon, newTheme);
|
||||
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
this.updateIconIfInViewport();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var desktopEntry = this.props.desktopEntry;
|
||||
var label = desktopEntry.Name;
|
||||
var category = desktopEntry.Categories;
|
||||
var icon = desktopEntry.Icon;
|
||||
|
||||
return (
|
||||
<li className="desktop-app">
|
||||
<img src={this.state.icon} className="desktop-app-icon" />
|
||||
<AppIcon className="desktop-app-icon" icon={icon} theme={this.props.theme} />
|
||||
<span className="desktop-app-label">{label}</span>
|
||||
</li>
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
_findIcon: function(iconPath, theme) {
|
||||
|
||||
var self = this;
|
||||
|
||||
console.log('Search icon %s:%s', iconPath, theme);
|
||||
|
||||
Util.DesktopApps.findIcon(iconPath || DEFAULT_ICON, theme)
|
||||
.then(function(iconPath) {
|
||||
if( !iconPath || /\.xpm$/.test(iconPath) ) {
|
||||
return Util.DesktopApps.findIcon(DEFAULT_ICON, theme);
|
||||
}
|
||||
return iconPath;
|
||||
})
|
||||
.then(function(iconPath) {
|
||||
global.window.requestAnimationFrame(function() {
|
||||
self.setState({ icon: iconPath });
|
||||
});
|
||||
})
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -9,30 +9,15 @@ module.exports = React.createClass({
|
|||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
desktopFiles: [],
|
||||
selectedTheme: null
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
|
||||
// Load system desktop apps
|
||||
var baseDirs = global.process.env.XDG_DATA_DIRS.split(':').map(function(baseDir){
|
||||
return path.join(baseDir, 'applications');
|
||||
});
|
||||
|
||||
Util.DesktopApps.loadAllDesktopFiles('/usr/share/applications')
|
||||
.then(function(desktopFiles) {
|
||||
this.setState({ desktopFiles: desktopFiles });
|
||||
}.bind(this))
|
||||
;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var items = this.state.desktopFiles.map(function(desktopFile, i) {
|
||||
var desktopEntry = desktopFile.content['Desktop Entry'];
|
||||
return <DesktopAppItem theme={this.state.selectedTheme} key={desktopFile.path} desktopEntry={desktopEntry} />;
|
||||
var items = this.props.desktopApps.map(function(desktopApp, i) {
|
||||
var desktopEntry = desktopApp.content['Desktop Entry'];
|
||||
return <DesktopAppItem theme={this.state.selectedTheme} key={desktopApp.path} desktopEntry={desktopEntry} />;
|
||||
}.bind(this));
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
var React = require('react');
|
||||
var connect = require('react-redux').connect;
|
||||
var DesktopAppList = require('./desktop-app-list.jsx');
|
||||
var actions = require('../actions');
|
||||
|
||||
module.exports = React.createClass({
|
||||
var EditView = React.createClass({
|
||||
|
||||
componentDidMount: function() {
|
||||
this.props.dispatch(actions.edit.loadDesktopApps());
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
return (
|
||||
<div className="edit">
|
||||
<DesktopAppList />
|
||||
<DesktopAppList desktopApps={this.props.desktopApps} />
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function select(state) {
|
||||
return {
|
||||
desktopApps: state.desktopApps
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = connect(select)(EditView);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
var redux = require('redux');
|
||||
var thunkMiddleware = require('redux-thunk');
|
||||
var loggerMiddleware = require('redux-logger');
|
||||
var reducers = require('./reducers');
|
||||
|
||||
var createStoreWithMiddleware = redux.applyMiddleware(
|
||||
thunkMiddleware
|
||||
)(redux.createStore);
|
||||
|
||||
var launcherReducers = redux.combineReducers({
|
||||
profile: reducers.profile,
|
||||
processOpts: reducers.processOpts
|
||||
});
|
||||
|
||||
var editReducers = redux.combineReducers({
|
||||
desktopApps: reducers.desktopApps,
|
||||
processOpts: reducers.processOpts
|
||||
});
|
||||
|
||||
exports.launcherStore = createStoreWithMiddleware(launcherReducers);
|
||||
exports.editStore = createStoreWithMiddleware(editReducers);
|
|
@ -0,0 +1,13 @@
|
|||
var actions = require('../../actions');
|
||||
|
||||
module.exports = function(state, action) {
|
||||
|
||||
var desktopApps = [];
|
||||
|
||||
if( action.type === actions.edit.LOAD_DESKTOP_APPS_SUCCESS ) {
|
||||
desktopApps = action.desktopApps;
|
||||
}
|
||||
|
||||
return desktopApps;
|
||||
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
exports.desktopApps = require('./desktop-apps');
|
||||
exports.profile = require('./profile');
|
||||
exports.processOpts = require('./process-opts');
|
|
@ -0,0 +1,8 @@
|
|||
var minimist = require('minimist');
|
||||
var gui = global.window.require('nw.gui');
|
||||
|
||||
var opts = minimist(gui.App.argv);
|
||||
|
||||
module.exports = function(state, action) {
|
||||
return opts;
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = function(state, action) {
|
||||
return {};
|
||||
};
|
|
@ -23,12 +23,17 @@
|
|||
"kiosk": false
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^3.3.5",
|
||||
"debug": "^2.2.0",
|
||||
"glob": "^5.0.14",
|
||||
"ini": "^1.3.4",
|
||||
"minimist": "^1.1.3",
|
||||
"node-jsx": "^0.13.3",
|
||||
"react": "^0.13.3",
|
||||
"react-dnd": "^1.1.5"
|
||||
"react-dnd": "^1.1.5",
|
||||
"react-redux": "^2.0.0",
|
||||
"redux": "^2.0.0",
|
||||
"redux-logger": "^1.0.6",
|
||||
"redux-thunk": "^0.1.0"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue