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;
|
height: 50px;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
display: inline-block;
|
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 gui = global.window.require('nw.gui');
|
||||||
var LauncherView = require('./components/launcher-view.jsx');
|
var LauncherView = require('./components/launcher-view.jsx');
|
||||||
var EditView = require('./components/edit-view.jsx');
|
var EditView = require('./components/edit-view.jsx');
|
||||||
|
var Provider = require('react-redux').Provider;
|
||||||
|
var stores = require('./stores');
|
||||||
|
|
||||||
// Internal constants
|
// Internal constants
|
||||||
var DEFAULT_PROFILE = './default-profile.json';
|
var DEFAULT_PROFILE = './default-profile.json';
|
||||||
var PROCESS_OPTS = minimist(gui.App.argv);
|
var PROCESS_OPTS = minimist(gui.App.argv);
|
||||||
|
|
||||||
|
|
||||||
// Main component
|
// Main component
|
||||||
var App = React.createClass({
|
var App = React.createClass({
|
||||||
|
|
||||||
|
@ -22,8 +23,12 @@ var App = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
|
|
||||||
var view = this.state.editMode ?
|
var view = this.state.editMode ?
|
||||||
<EditView profilePath={this.state.profilePath} /> :
|
<Provider store={stores.editStore}>
|
||||||
<LauncherView profilePath={this.state.profilePath ? this.state.profilePath : DEFAULT_PROFILE } />
|
{ 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 (
|
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 React = require('react');
|
||||||
var Util = require('../util');
|
var Util = require('../util');
|
||||||
var LazyLoad = require('./mixins/lazy-load');
|
var AppIcon = require('./app-icon.jsx');
|
||||||
|
|
||||||
var LOADING_ICON = 'img/hourglass.svg';
|
|
||||||
var DEFAULT_ICON = 'img/default-icon.svg';
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
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() {
|
render: function() {
|
||||||
|
|
||||||
var desktopEntry = this.props.desktopEntry;
|
var desktopEntry = this.props.desktopEntry;
|
||||||
var label = desktopEntry.Name;
|
var label = desktopEntry.Name;
|
||||||
var category = desktopEntry.Categories;
|
var category = desktopEntry.Categories;
|
||||||
|
var icon = desktopEntry.Icon;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="desktop-app">
|
<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>
|
<span className="desktop-app-label">{label}</span>
|
||||||
</li>
|
</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() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
desktopFiles: [],
|
|
||||||
selectedTheme: null
|
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() {
|
render: function() {
|
||||||
|
|
||||||
var items = this.state.desktopFiles.map(function(desktopFile, i) {
|
var items = this.props.desktopApps.map(function(desktopApp, i) {
|
||||||
var desktopEntry = desktopFile.content['Desktop Entry'];
|
var desktopEntry = desktopApp.content['Desktop Entry'];
|
||||||
return <DesktopAppItem theme={this.state.selectedTheme} key={desktopFile.path} desktopEntry={desktopEntry} />;
|
return <DesktopAppItem theme={this.state.selectedTheme} key={desktopApp.path} desktopEntry={desktopEntry} />;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,16 +1,30 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
|
var connect = require('react-redux').connect;
|
||||||
var DesktopAppList = require('./desktop-app-list.jsx');
|
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() {
|
render: function() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="edit">
|
<div className="edit">
|
||||||
<DesktopAppList />
|
<DesktopAppList desktopApps={this.props.desktopApps} />
|
||||||
</div>
|
</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
|
"kiosk": false
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bootstrap": "^3.3.5",
|
||||||
"debug": "^2.2.0",
|
"debug": "^2.2.0",
|
||||||
"glob": "^5.0.14",
|
"glob": "^5.0.14",
|
||||||
"ini": "^1.3.4",
|
"ini": "^1.3.4",
|
||||||
"minimist": "^1.1.3",
|
"minimist": "^1.1.3",
|
||||||
"node-jsx": "^0.13.3",
|
"node-jsx": "^0.13.3",
|
||||||
"react": "^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