Merge branch 'feature/electron' into develop
This commit is contained in:
commit
7db3d9eb69
|
@ -7,3 +7,4 @@ dist
|
||||||
build
|
build
|
||||||
nwjs
|
nwjs
|
||||||
my-profile.json
|
my-profile.json
|
||||||
|
js-compiled
|
||||||
|
|
118
Gruntfile.js
118
Gruntfile.js
|
@ -1,118 +0,0 @@
|
||||||
/* jshint node: true */
|
|
||||||
var _ = require('lodash');
|
|
||||||
var path = require('path');
|
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
|
||||||
|
|
||||||
var NW_VERSION = '0.12.3';
|
|
||||||
var BUILD_DIR = 'build';
|
|
||||||
var BUILD_TARGETS = {
|
|
||||||
linux_ia32: true,
|
|
||||||
linux_x64: true,
|
|
||||||
win: false,
|
|
||||||
osx: false
|
|
||||||
};
|
|
||||||
var PKG = grunt.file.readJSON('package.json');
|
|
||||||
var PKG_OVERWRITE = {
|
|
||||||
window: {
|
|
||||||
toolbar: false,
|
|
||||||
kiosk: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create build tasks options
|
|
||||||
var buildOptions = _.merge({
|
|
||||||
runtimeVersion: NW_VERSION
|
|
||||||
}, BUILD_TARGETS);
|
|
||||||
|
|
||||||
// Define copy:build tasks files
|
|
||||||
var appFiles = [];
|
|
||||||
|
|
||||||
_.forEach(BUILD_TARGETS, function(isEnabled, target) {
|
|
||||||
|
|
||||||
if(!isEnabled) return;
|
|
||||||
|
|
||||||
var arch = 'ia32';
|
|
||||||
var platform = target;
|
|
||||||
if(platform.indexOf('linux') !== -1) {
|
|
||||||
arch = platform.split('_')[1];
|
|
||||||
platform = 'linux';
|
|
||||||
}
|
|
||||||
var dirName = PKG.name + '-' + PKG.version + '-' + platform + '-' + arch;
|
|
||||||
var destPath = path.join(BUILD_DIR, dirName + '/');
|
|
||||||
|
|
||||||
// Retreive NPM dependencies
|
|
||||||
var npmDeps = _.keys(PKG.dependencies).map(function(moduleName) {
|
|
||||||
return path.join('node_modules', moduleName, '**');
|
|
||||||
});
|
|
||||||
appFiles.push({ src: npmDeps, dest: destPath });
|
|
||||||
|
|
||||||
// Add main files, licence, & config
|
|
||||||
appFiles.push({
|
|
||||||
src: [
|
|
||||||
'index.html',
|
|
||||||
'package.json',
|
|
||||||
'default-profile.json',
|
|
||||||
'LICENCE',
|
|
||||||
'css/**',
|
|
||||||
'js/**',
|
|
||||||
'img/**'
|
|
||||||
],
|
|
||||||
dest: destPath
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Configure tasks
|
|
||||||
grunt.initConfig({
|
|
||||||
|
|
||||||
pkg: PKG,
|
|
||||||
|
|
||||||
download: {
|
|
||||||
options: {
|
|
||||||
runtimeVersion: NW_VERSION
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
run: {
|
|
||||||
options: {
|
|
||||||
nwArgs: ['.'].concat(process.argv.slice(3)),
|
|
||||||
runtimeVersion: NW_VERSION
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
build: {
|
|
||||||
options: buildOptions
|
|
||||||
},
|
|
||||||
|
|
||||||
clean: {
|
|
||||||
build: [BUILD_DIR]
|
|
||||||
},
|
|
||||||
|
|
||||||
copy: {
|
|
||||||
build: {
|
|
||||||
files: appFiles,
|
|
||||||
options: {
|
|
||||||
noProcess: ['**','!package.json'],
|
|
||||||
process: function() {
|
|
||||||
var pkg = _.merge(PKG, PKG_OVERWRITE);
|
|
||||||
return JSON.stringify(pkg, null, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
grunt.registerTask('pitaya:run', ['download', 'run']);
|
|
||||||
grunt.registerTask(
|
|
||||||
'pitaya:build',
|
|
||||||
['download', 'build', 'copy:build']
|
|
||||||
);
|
|
||||||
grunt.registerTask('default', ['pitaya:run']);
|
|
||||||
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
|
||||||
grunt.loadNpmTasks('grunt-nw');
|
|
||||||
|
|
||||||
};
|
|
28
README.md
28
README.md
|
@ -9,33 +9,25 @@ Lanceur d'application pour GNU/Linux
|
||||||
- [NodeJS](https://nodejs.org/) - Dernière version stable, testé sur la 0.12.*
|
- [NodeJS](https://nodejs.org/) - Dernière version stable, testé sur la 0.12.*
|
||||||
- [NPM](https://www.npmjs.com/) - Normalement automatiquement installé avec NodeJS.
|
- [NPM](https://www.npmjs.com/) - Normalement automatiquement installé avec NodeJS.
|
||||||
|
|
||||||
### Initialisation du projet
|
### Initialisation du projet & lancement de Pitaya
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://forge.cadoles.com/wpetit/pitaya.git
|
git clone https://forge.cadoles.com/wpetit/pitaya.git
|
||||||
cd pitaya
|
cd pitaya
|
||||||
git checkout develop
|
git checkout develop
|
||||||
npm install
|
npm install
|
||||||
DEBUG=pitaya* npm start
|
DEBUG=pitaya* NODE_ENV=development npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Variables d'environnement
|
||||||
|
|
||||||
```
|
Vous pouvez configurer le comportement de Pitaya en passant des variables d'environnement:
|
||||||
--profile=<chemin_profile> Chemin vers le fichier de profil à charger dans l'application.
|
|
||||||
--edit Ouvrir l'application en mode édition.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Passer des options en développement
|
| Variable | Description | Valeurs possibles | Valeur par défaut |
|
||||||
|
|-------------------|------------------------------------|-------------------|------------------------|
|
||||||
```
|
| PITAYA_MODE | Mode d'exécution de Pitaya | launcher, edit | launcher |
|
||||||
npm start -- [options...]
|
| PITAYA_PROFILE | Chemin du fichier profil à charger | -- | ./default-profile.json |
|
||||||
```
|
| PITAYA_AS_DESKTOP | Afficher Pitaya en mode "Bureau" | 1, 0 | 0 |
|
||||||
|
|
||||||
Exemple:
|
|
||||||
```
|
|
||||||
npm start -- --profile=my-profile.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Comment construire l'application depuis les sources
|
## Comment construire l'application depuis les sources
|
||||||
|
|
||||||
|
@ -43,7 +35,7 @@ npm start -- --profile=my-profile.json
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Un dossier `pitaya-<version>-<target>-<arch>` sera créé dans le répertoire `./build`. Celui ci contient tous les fichiers nécessaires à l'application.
|
Un dossier `pitaya-<target>-<arch>` sera créé dans le répertoire `./build`. Celui ci contient tous les fichiers nécessaires à l'application.
|
||||||
|
|
||||||
|
|
||||||
## Comment contribuer
|
## Comment contribuer
|
||||||
|
|
|
@ -27,21 +27,42 @@ html, body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: url('../img/background.png') no-repeat;
|
background: url('../img/background.png');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center center;
|
||||||
|
transition: background-image 250ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.launcher .main {
|
||||||
|
flex-direction: row;
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.launcher .nav {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.launcher .nav a.goback {
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
font-size: 60px;
|
||||||
|
text-shadow: 1px 1px #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.launcher .nav a.goback:hover {
|
||||||
|
-webkit-animation: 500ms pulse-large infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.launcher .category-header {
|
.launcher .category-header {
|
||||||
padding: 40px 50px 0;
|
padding: 25px 40px 0;
|
||||||
font-size: 50px;
|
font-size: 50px;
|
||||||
}
|
color: #fff;
|
||||||
|
text-shadow: 1px 1px #444;
|
||||||
.launcher .category-header a.goback {
|
|
||||||
text-decoration: none;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.launcher .category-header a.goback:hover {
|
|
||||||
-webkit-animation: 500ms pulse-large infinite;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.launcher .category-header > .category-label {
|
.launcher .category-header > .category-label {
|
||||||
|
@ -65,6 +86,10 @@ html, body {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.launcher .nav ~ ul.apps-list {
|
||||||
|
margin-left: -50px;
|
||||||
|
}
|
||||||
|
|
||||||
.launcher li.app-item {
|
.launcher li.app-item {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -221,7 +246,7 @@ html, body {
|
||||||
|
|
||||||
@-webkit-keyframes pulse-large {
|
@-webkit-keyframes pulse-large {
|
||||||
0% { transform: scale(1); }
|
0% { transform: scale(1); }
|
||||||
50% { transform: scale(1.5); }
|
50% { transform: scale(1.3); }
|
||||||
100% { transform: scale(1); }
|
100% { transform: scale(1); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
{
|
{
|
||||||
"label": "Level 1",
|
"label": "Level 1",
|
||||||
"icon": "chromium-browser",
|
"icon": "chromium-browser",
|
||||||
|
"background": "./img/background2.jpg",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"label": "Level 2-1",
|
"label": "Level 2-1",
|
||||||
|
@ -11,9 +12,11 @@
|
||||||
{
|
{
|
||||||
"label": "Chromium Browser 1",
|
"label": "Chromium Browser 1",
|
||||||
"icon": "chromium-browser",
|
"icon": "chromium-browser",
|
||||||
"exec": "/usr/bin/chromium-browser"
|
"exec": "/usr/bin/chromium-browser",
|
||||||
|
"_key": "item_1444480285022_3"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"_key": "item_1444480285022_2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Level 2-2",
|
"label": "Level 2-2",
|
||||||
|
@ -26,13 +29,24 @@
|
||||||
{
|
{
|
||||||
"label": "Chromium Browser 2",
|
"label": "Chromium Browser 2",
|
||||||
"icon": "chromium-browser",
|
"icon": "chromium-browser",
|
||||||
"exec": "/usr/bin/chromium-browser"
|
"exec": "/usr/bin/chromium-browser",
|
||||||
|
"_key": "item_1444480285022_6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Atom",
|
||||||
|
"icon": "atom",
|
||||||
|
"exec": "/usr/share/atom/atom %U",
|
||||||
|
"_key": "item_1444480288996_7"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"_key": "item_1444480285022_5"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"_key": "item_1444480285022_4"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"_key": "item_1444480285022_1"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"_key": "item_1444480285021_0"
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 903 KiB |
13
index.html
13
index.html
|
@ -15,11 +15,16 @@
|
||||||
global.document = global.window.document;
|
global.document = global.window.document;
|
||||||
global.navigator = global.window.navigator;
|
global.navigator = global.window.navigator;
|
||||||
|
|
||||||
// Auto transform JSX
|
var isDev = process.env.NODE_ENV === 'development';
|
||||||
require('node-jsx').install();
|
|
||||||
|
|
||||||
// Launch application
|
if(isDev) {
|
||||||
require('./js/app.jsx');
|
// Auto transform JSX
|
||||||
|
require('node-jsx').install({extension: '.js'});
|
||||||
|
// Launch application
|
||||||
|
require('./js/app.js');
|
||||||
|
} else {
|
||||||
|
require('./js-compiled/app.js');
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var LauncherView = require('./components/launcher/launcher-view.jsx');
|
var LauncherView = require('./components/launcher/launcher-view.js');
|
||||||
var EditView = require('./components/edit/edit-view.jsx');
|
var EditView = require('./components/edit/edit-view.js');
|
||||||
var Provider = require('react-redux').Provider;
|
var Provider = require('react-redux').Provider;
|
||||||
var connect = require('react-redux').connect;
|
var connect = require('react-redux').connect;
|
||||||
var store = require('./store');
|
var store = require('./store');
|
||||||
|
@ -10,7 +10,7 @@ var App = React.createClass({
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
|
||||||
var editMode = this.props.processOpts.edit || false;
|
var editMode = process.env.PITAYA_MODE === 'edit';
|
||||||
|
|
||||||
var view = editMode ? <EditView /> : <LauncherView />;
|
var view = editMode ? <EditView /> : <LauncherView />;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var Util = require('../../util');
|
var Util = require('../../util');
|
||||||
var AppIcon = require('../common/app-icon.jsx');
|
var AppIcon = require('../common/app-icon.js');
|
||||||
var DragSource = require('react-dnd').DragSource;
|
var DragSource = require('react-dnd').DragSource;
|
||||||
|
|
||||||
var DesktopAppItem = React.createClass({
|
var DesktopAppItem = React.createClass({
|
|
@ -1,6 +1,6 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var Util = require('../../util');
|
var Util = require('../../util');
|
||||||
var DesktopAppItem = require('./desktop-app-item.jsx');
|
var DesktopAppItem = require('./desktop-app-item.js');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var debug = require('../../util/debug')('pitaya:desktop-app-list');
|
var debug = require('../../util/debug')('pitaya:desktop-app-list');
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var connect = require('react-redux').connect;
|
var connect = require('react-redux').connect;
|
||||||
var ProfileTree = require('./profile-tree.jsx');
|
var ProfileTree = require('./profile-tree.js');
|
||||||
var DesktopAppList = require('./desktop-app-list.jsx');
|
var DesktopAppList = require('./desktop-app-list.js');
|
||||||
var ItemForm = require('./item-form.jsx');
|
var ItemForm = require('./item-form.js');
|
||||||
var IconThemeSelector = require('./icon-theme-selector.jsx');
|
var IconThemeSelector = require('./icon-theme-selector.js');
|
||||||
var ProfileMenu = require('./profile-menu.jsx');
|
var ProfileMenu = require('./profile-menu.js');
|
||||||
var tree = require('../../util/tree');
|
var tree = require('../../util/tree');
|
||||||
|
|
||||||
var actions = require('../../store/actions');
|
var actions = require('../../store/actions');
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* jhsint node:true, jsx: true */
|
||||||
|
var React = require('react');
|
||||||
|
var connect = require('react-redux').connect;
|
||||||
|
var actions = require('../../store/actions');
|
||||||
|
var dialog = require('remote').require('dialog');
|
||||||
|
|
||||||
|
var ProfileMenu = React.createClass({
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="profile-menu">
|
||||||
|
<button className="btn btn-default" onClick={this.handleOpenClick}>Ouvrir</button>
|
||||||
|
<button className="btn btn-primary" onClick={this.handleSaveClick}>Enregistrer</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOpenClick: function() {
|
||||||
|
var dispatch = this.props.dispatch;
|
||||||
|
this.showOpenProfileDialog()
|
||||||
|
.then(function(profilePath) {
|
||||||
|
if(profilePath) dispatch(actions.common.loadProfile(profilePath));
|
||||||
|
})
|
||||||
|
;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSaveClick: function() {
|
||||||
|
|
||||||
|
var dispatch = this.props.dispatch;
|
||||||
|
var profile = this.props.profile;
|
||||||
|
var profilePath = this.props.profilePath;
|
||||||
|
|
||||||
|
this.showSaveProfileDialog(profilePath)
|
||||||
|
.then(function(profilePath) {
|
||||||
|
if(profilePath) dispatch(actions.edit.saveProfile(profilePath, profile));
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
showOpenProfileDialog: function() {
|
||||||
|
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
dialog.showOpenDialog(
|
||||||
|
{
|
||||||
|
title: 'Éditer un profil',
|
||||||
|
filters: [ {name: 'Profils Pitaya', extensions: ['json'] } ],
|
||||||
|
properties: ['openFile']
|
||||||
|
},
|
||||||
|
function(files) {
|
||||||
|
return resolve(files ? files[0] : null);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
showSaveProfileDialog: function(defaultPath) {
|
||||||
|
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
dialog.showSaveDialog(
|
||||||
|
{
|
||||||
|
defaultPath: defaultPath,
|
||||||
|
title: 'Enregistrer un profil',
|
||||||
|
filters: [ {name: 'Profils Pitaya', extensions: ['json'] } ]
|
||||||
|
},
|
||||||
|
function(file) {
|
||||||
|
return resolve(file);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function select(state) {
|
||||||
|
return {
|
||||||
|
profile: state.profile,
|
||||||
|
profilePath: state.profilePath
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = connect(select)(ProfileMenu);
|
|
@ -1,79 +0,0 @@
|
||||||
var React = require('react');
|
|
||||||
var connect = require('react-redux').connect;
|
|
||||||
var actions = require('../../store/actions');
|
|
||||||
|
|
||||||
var ProfileMenu = React.createClass({
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="profile-menu">
|
|
||||||
<input ref="fileInput" style={{display: 'none'}} filter=".json" type="file" />
|
|
||||||
<button className="btn btn-default" onClick={this.handleOpenClick}>Ouvrir</button>
|
|
||||||
<button className="btn btn-primary" onClick={this.handleSaveClick}>Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
handleOpenClick: function() {
|
|
||||||
var dispatch = this.props.dispatch;
|
|
||||||
this.showFileDialog()
|
|
||||||
.then(function(profilePath) {
|
|
||||||
dispatch(actions.common.loadProfile(profilePath));
|
|
||||||
})
|
|
||||||
;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSaveClick: function() {
|
|
||||||
|
|
||||||
var dispatch = this.props.dispatch;
|
|
||||||
var profile = this.props.profile;
|
|
||||||
var profilePath = this.props.profilePath;
|
|
||||||
|
|
||||||
var promise = profilePath ? Promise.resolve(profilePath) : this.showFileDialog(true);
|
|
||||||
|
|
||||||
promise.then(function(profilePath) {
|
|
||||||
dispatch(actions.edit.saveProfile(profilePath, profile));
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
showFileDialog: function(saveAs) {
|
|
||||||
|
|
||||||
var fileInput = this.refs.fileInput.getDOMNode();
|
|
||||||
|
|
||||||
// Toggle 'save as' feature
|
|
||||||
if(saveAs) {
|
|
||||||
fileInput.nwsaveas = true;
|
|
||||||
} else {
|
|
||||||
fileInput.removeAttribute('nwsaveas');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
|
|
||||||
fileInput.addEventListener('change', handleChange, false);
|
|
||||||
fileInput.click();
|
|
||||||
|
|
||||||
function handleChange(evt) {
|
|
||||||
fileInput.removeEventListener('change', handleChange);
|
|
||||||
var value = this.value;
|
|
||||||
this.value = null;
|
|
||||||
resolve(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
function select(state) {
|
|
||||||
return {
|
|
||||||
profile: state.profile,
|
|
||||||
profilePath: state.profilePath
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = connect(select)(ProfileMenu);
|
|
|
@ -1,7 +1,7 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var connect = require('react-redux').connect;
|
var connect = require('react-redux').connect;
|
||||||
var actions = require('../../store/actions');
|
var actions = require('../../store/actions');
|
||||||
var TreeItem = require('./tree-item.jsx');
|
var TreeItem = require('./tree-item.js');
|
||||||
|
|
||||||
var TreeNode = React.createClass({
|
var TreeNode = React.createClass({
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ var TreeNode = React.createClass({
|
||||||
selectedItem={this.props.selectedItem}
|
selectedItem={this.props.selectedItem}
|
||||||
onItemClicked={this.props.onItemClicked}
|
onItemClicked={this.props.onItemClicked}
|
||||||
onItemMoved={this.props.onItemMoved}
|
onItemMoved={this.props.onItemMoved}
|
||||||
|
onItemRemoved={this.props.onItemRemoved}
|
||||||
theme={this.props.theme} />
|
theme={this.props.theme} />
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
@ -66,6 +67,7 @@ var ProfileTree = React.createClass({
|
||||||
selectedItem={this.props.selectedItem}
|
selectedItem={this.props.selectedItem}
|
||||||
onItemClicked={this.onItemSelected}
|
onItemClicked={this.onItemSelected}
|
||||||
onItemMoved={this.onItemMoved}
|
onItemMoved={this.onItemMoved}
|
||||||
|
onItemRemoved={this.onItemRemoved}
|
||||||
theme={this.props.theme} />
|
theme={this.props.theme} />
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -76,6 +78,10 @@ var ProfileTree = React.createClass({
|
||||||
|
|
||||||
onItemSelected: function(selectedItem) {
|
onItemSelected: function(selectedItem) {
|
||||||
this.props.dispatch(actions.edit.selectProfileItem(selectedItem));
|
this.props.dispatch(actions.edit.selectProfileItem(selectedItem));
|
||||||
|
},
|
||||||
|
|
||||||
|
onItemRemoved: function(selectedItem) {
|
||||||
|
this.props.dispatch(actions.edit.removeProfileItem(selectedItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
var React = require('react/addons');
|
var React = require('react/addons');
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
var AppIcon = require('../common/app-icon.jsx');
|
var AppIcon = require('../common/app-icon.js');
|
||||||
var DragSource = require('react-dnd').DragSource;
|
var DragSource = require('react-dnd').DragSource;
|
||||||
var DropTarget = require('react-dnd').DropTarget;
|
var DropTarget = require('react-dnd').DropTarget;
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
@ -30,6 +30,9 @@ var TreeItem = React.createClass({
|
||||||
<div className={classes} style={style} onClick={this.handleClick}>
|
<div className={classes} style={style} onClick={this.handleClick}>
|
||||||
{appIcon}
|
{appIcon}
|
||||||
<span className="app-label">{data.label}</span>
|
<span className="app-label">{data.label}</span>
|
||||||
|
<button type="button" className="close pull-right" onClick={this.handleRemoveClick}>
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -38,6 +41,11 @@ var TreeItem = React.createClass({
|
||||||
handleClick: function(evt) {
|
handleClick: function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
this.props.onItemClicked(this.props.data);
|
this.props.onItemClicked(this.props.data);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleRemoveClick: function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
this.props.onItemRemoved(this.props.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
|
@ -1,5 +1,5 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var AppIcon = require('../common/app-icon.jsx');
|
var AppIcon = require('../common/app-icon.js');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var AppItem = require('./app-item.jsx');
|
var AppItem = require('./app-item.js');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
var React = require('react');
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
item: React.PropTypes.object.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="category-header">
|
||||||
|
<span className="category-label">{this.props.item.label}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
|
@ -1,12 +1,14 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var CategoryHeader = require('./category-header.jsx');
|
var CategoryHeader = require('./category-header.js');
|
||||||
var AppList = require('./app-list.jsx');
|
var AppList = require('./app-list.js');
|
||||||
|
var Nav = require('./nav.js');
|
||||||
var AnimateMixin = require('../mixins/animate');
|
var AnimateMixin = require('../mixins/animate');
|
||||||
var actions = require('../../store/actions');
|
var actions = require('../../store/actions');
|
||||||
var connect = require('react-redux').connect;
|
var connect = require('react-redux').connect;
|
||||||
var debug = require('../../util/debug')('launcher-view');
|
var debug = require('../../util/debug')('launcher-view');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
var DEFAULT_PROFILE = './default-profile.json';
|
var DEFAULT_PROFILE = path.join(__dirname, '..', '..', '..', 'default-profile.json');
|
||||||
|
|
||||||
var LauncherView = React.createClass({
|
var LauncherView = React.createClass({
|
||||||
|
|
||||||
|
@ -20,7 +22,7 @@ var LauncherView = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
var profilePath = this.props.processOpts.profile || DEFAULT_PROFILE;
|
var profilePath = process.env.PITAYA_PROFILE || DEFAULT_PROFILE;
|
||||||
this.props.dispatch(actions.common.loadProfile(profilePath));
|
this.props.dispatch(actions.common.loadProfile(profilePath));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -38,19 +40,34 @@ var LauncherView = React.createClass({
|
||||||
|
|
||||||
var header = currentItemPath !== '' ?
|
var header = currentItemPath !== '' ?
|
||||||
( <CategoryHeader
|
( <CategoryHeader
|
||||||
|
item={currentItem} /> ) :
|
||||||
|
null
|
||||||
|
;
|
||||||
|
|
||||||
|
var nav = currentItemPath !== '' ?
|
||||||
|
( <Nav
|
||||||
onBackClick={this.onBackClick}
|
onBackClick={this.onBackClick}
|
||||||
item={currentItem}
|
item={currentItem}
|
||||||
itemPath={currentItemPath} /> ) :
|
itemPath={currentItemPath} /> ) :
|
||||||
null
|
null
|
||||||
;
|
;
|
||||||
|
|
||||||
|
var style = {};
|
||||||
|
|
||||||
|
if(currentItem && currentItem.background) {
|
||||||
|
style.backgroundImage = 'url('+currentItem.background+')';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="launcher">
|
<div className="launcher" style={style}>
|
||||||
{header}
|
{header}
|
||||||
<AppList ref="appList"
|
<div className="main">
|
||||||
items={items}
|
{nav}
|
||||||
parentPath={currentItemPath}
|
<AppList ref="appList"
|
||||||
onItemClick={this.onItemClick} />
|
items={items}
|
||||||
|
parentPath={currentItemPath}
|
||||||
|
onItemClick={this.onItemClick} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* jshint node: true jsx: true */
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
@ -14,9 +15,8 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="category-header">
|
<div className="nav">
|
||||||
<a href="#" onClick={this._onBackClick} className="goback" >◄</a>
|
<a href="#" onClick={this._onBackClick} className="goback" >◄</a>
|
||||||
<span className="category-label">{this.props.item.label}</span>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,6 +12,7 @@ var SAVE_PROFILE_FAILED = exports.SAVE_PROFILE_FAILED = 'SAVE_PROFILE_FAILED';
|
||||||
|
|
||||||
var MOVE_PROFILE_ITEM = exports.MOVE_PROFILE_ITEM = 'MOVE_PROFILE_ITEM';
|
var MOVE_PROFILE_ITEM = exports.MOVE_PROFILE_ITEM = 'MOVE_PROFILE_ITEM';
|
||||||
var ADD_PROFILE_ITEM = exports.ADD_PROFILE_ITEM = 'ADD_PROFILE_ITEM';
|
var ADD_PROFILE_ITEM = exports.ADD_PROFILE_ITEM = 'ADD_PROFILE_ITEM';
|
||||||
|
var REMOVE_PROFILE_ITEM = exports.REMOVE_PROFILE_ITEM = 'REMOVE_PROFILE_ITEM';
|
||||||
var USE_ICON_THEME = exports.USE_ICON_THEME = 'USE_ICON_THEME';
|
var USE_ICON_THEME = exports.USE_ICON_THEME = 'USE_ICON_THEME';
|
||||||
var SELECT_PROFILE_ITEM = exports.SELECT_PROFILE_ITEM = 'SELECT_PROFILE_ITEM';
|
var SELECT_PROFILE_ITEM = exports.SELECT_PROFILE_ITEM = 'SELECT_PROFILE_ITEM';
|
||||||
var UPDATE_PROFILE_ITEM = exports.UPDATE_PROFILE_ITEM = 'UPDATE_PROFILE_ITEM';
|
var UPDATE_PROFILE_ITEM = exports.UPDATE_PROFILE_ITEM = 'UPDATE_PROFILE_ITEM';
|
||||||
|
@ -71,6 +72,13 @@ exports.moveProfileItem = function(movedItem, targetItem) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.removeProfileItem = function(removedItem) {
|
||||||
|
return {
|
||||||
|
type: REMOVE_PROFILE_ITEM,
|
||||||
|
removedItem: removedItem
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
exports.addProfileItem = function(newItem, targetItem) {
|
exports.addProfileItem = function(newItem, targetItem) {
|
||||||
return {
|
return {
|
||||||
type: ADD_PROFILE_ITEM,
|
type: ADD_PROFILE_ITEM,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
var redux = require('redux');
|
var redux = require('redux');
|
||||||
var thunkMiddleware = require('redux-thunk');
|
var thunkMiddleware = require('redux-thunk');
|
||||||
var loggerMiddleware = require('redux-logger');
|
|
||||||
var reducers = require('./reducers');
|
var reducers = require('./reducers');
|
||||||
var loggerMiddleware = require('./middlewares/logger');
|
var loggerMiddleware = require('./middlewares/logger');
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
exports.desktopApps = require('./desktop-apps');
|
exports.desktopApps = require('./desktop-apps');
|
||||||
exports.profile = require('./profile');
|
exports.profile = require('./profile');
|
||||||
exports.processOpts = require('./process-opts');
|
|
||||||
exports.theme = require('./theme');
|
exports.theme = require('./theme');
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
var minimist = require('minimist');
|
|
||||||
var gui = global.window.require('nw.gui');
|
|
||||||
|
|
||||||
var opts = minimist(gui.App.argv);
|
|
||||||
|
|
||||||
module.exports = function(state, action) {
|
|
||||||
return opts;
|
|
||||||
};
|
|
|
@ -14,6 +14,9 @@ module.exports = function(oldProfile, action) {
|
||||||
case actions.edit.MOVE_PROFILE_ITEM:
|
case actions.edit.MOVE_PROFILE_ITEM:
|
||||||
return moveProfileItem(oldProfile, action.movedItem, action.targetItem);
|
return moveProfileItem(oldProfile, action.movedItem, action.targetItem);
|
||||||
|
|
||||||
|
case actions.edit.REMOVE_PROFILE_ITEM:
|
||||||
|
return removeProfileItem(oldProfile, action.removedItem);
|
||||||
|
|
||||||
case actions.edit.ADD_PROFILE_ITEM:
|
case actions.edit.ADD_PROFILE_ITEM:
|
||||||
return addProfileItem(oldProfile, action.newItem, action.targetItem);
|
return addProfileItem(oldProfile, action.newItem, action.targetItem);
|
||||||
|
|
||||||
|
@ -48,6 +51,18 @@ function updateProfileItem(oldProfile, targetItem, key, value) {
|
||||||
return newProfile;
|
return newProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeProfileItem(oldProfile, removedItem) {
|
||||||
|
|
||||||
|
var newProfile = _.cloneDeep(oldProfile);
|
||||||
|
var parent = tree.find(newProfile, removedItem).parent;
|
||||||
|
|
||||||
|
parent.items = _.reject(parent.items, function(item) {
|
||||||
|
return _.isEqual(item, removedItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
return newProfile;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function moveProfileItem(oldProfile, movedItem, targetItem) {
|
function moveProfileItem(oldProfile, movedItem, targetItem) {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
exports.EDIT_MODE = 'edit';
|
||||||
|
exports.LAUNCHER_MODE = 'launcher';
|
|
@ -3,15 +3,5 @@ var util = require('util');
|
||||||
|
|
||||||
module.exports = function createLogger(namespace) {
|
module.exports = function createLogger(namespace) {
|
||||||
var logger = debug('pitaya:'+namespace);
|
var logger = debug('pitaya:'+namespace);
|
||||||
var isNWContext = 'window' in global;
|
|
||||||
var console = isNWContext ? global.window.console : global.console;
|
|
||||||
logger.log = function() {
|
|
||||||
if(isNWContext) {
|
|
||||||
console.log.apply(console, arguments);
|
|
||||||
} else {
|
|
||||||
var str = util.format.apply(util, arguments);
|
|
||||||
console.log(str);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return logger;
|
return logger;
|
||||||
};
|
};
|
||||||
|
|
|
@ -249,7 +249,9 @@ exports.findPixmapsIcon = function(iconName) {
|
||||||
exports.findIconThemes = function() {
|
exports.findIconThemes = function() {
|
||||||
return System.findFiles('*/', {cwd: ICON_THEMES_ROOTDIR, realpath: true})
|
return System.findFiles('*/', {cwd: ICON_THEMES_ROOTDIR, realpath: true})
|
||||||
.then(function(files) {
|
.then(function(files) {
|
||||||
return files.map(path.basename.bind(path));
|
return files.map(function(f) {
|
||||||
|
return path.basename(f);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
var app = require('app'); // Module to control application life.
|
||||||
|
var BrowserWindow = require('browser-window'); // Module to create native browser window.
|
||||||
|
var isDev = process.env.NODE_ENV === 'development';
|
||||||
|
var constants = require('./'+(isDev ? 'js': 'js-compiled')+'/util/const');
|
||||||
|
|
||||||
|
var mainWindow = null;
|
||||||
|
|
||||||
|
// Quit when all windows are closed.
|
||||||
|
app.on('window-all-closed', function() {
|
||||||
|
app.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('ready', function() {
|
||||||
|
// Create the browser window.
|
||||||
|
var electronScreen = require('screen');
|
||||||
|
var size = electronScreen.getPrimaryDisplay().workAreaSize;
|
||||||
|
|
||||||
|
var asDesktop = process.env.PITAYA_AS_DESKTOP == 1;
|
||||||
|
|
||||||
|
mainWindow = new BrowserWindow({
|
||||||
|
type: asDesktop ? 'desktop' : undefined,
|
||||||
|
'skip-taskbar': asDesktop,
|
||||||
|
frame: !asDesktop,
|
||||||
|
width: asDesktop ? size.width : undefined,
|
||||||
|
height: asDesktop ? size.height : undefined,
|
||||||
|
x: asDesktop ? 0 : undefined,
|
||||||
|
y: asDesktop ? 0 : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
if(process.env.NODE_ENV === 'development') {
|
||||||
|
mainWindow.openDevTools();
|
||||||
|
}
|
||||||
|
|
||||||
|
// and load the index.html of the app.
|
||||||
|
mainWindow.loadUrl('file://' + __dirname + '/index.html');
|
||||||
|
|
||||||
|
mainWindow.on('closed', function() {
|
||||||
|
mainWindow = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
28
package.json
28
package.json
|
@ -2,25 +2,21 @@
|
||||||
"name": "pitaya",
|
"name": "pitaya",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"main": "index.html",
|
"main": "main.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"grunt": "^0.4.5",
|
"electron-packager": "^5.1.0",
|
||||||
"grunt-cli": "^0.1.13",
|
"electron-prebuilt": "^0.33.6",
|
||||||
"grunt-contrib-clean": "^0.6.0",
|
"nodeunit": "^0.9.1",
|
||||||
"grunt-contrib-copy": "^0.7.0",
|
"react-tools": "^0.13.3",
|
||||||
"grunt-nw": "git+https://github.com/snap-project/grunt-nw#develop",
|
"node-jsx": "^0.13.3"
|
||||||
"lodash": "^3.0.1",
|
|
||||||
"nodeunit": "^0.9.1"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "./node_modules/.bin/nodeunit test",
|
"test": "./node_modules/.bin/nodeunit test",
|
||||||
"start": "./node_modules/.bin/grunt pitaya:run",
|
"start": "./node_modules/.bin/electron .",
|
||||||
"build": "./node_modules/.bin/grunt pitaya:build"
|
"compile": "./node_modules/.bin/jsx -x js js js-compiled",
|
||||||
},
|
"clean": "rm -rf js-compiled/* build/*",
|
||||||
"chromium-args": "--ignore-certificate-errors",
|
"package": "./node_modules/.bin/electron-packager ./ pitaya --prune --ignore=js/ --platform=linux --arch=ia32 --version=0.33.6 --out=build --overwrite --app-version 0.0.0",
|
||||||
"window": {
|
"build": "npm run clean && npm run compile && npm run package"
|
||||||
"toolbar": true,
|
|
||||||
"kiosk": false
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap": "^3.3.5",
|
"bootstrap": "^3.3.5",
|
||||||
|
@ -29,8 +25,6 @@
|
||||||
"glob": "^5.0.14",
|
"glob": "^5.0.14",
|
||||||
"ini": "^1.3.4",
|
"ini": "^1.3.4",
|
||||||
"lodash": "^3.10.1",
|
"lodash": "^3.10.1",
|
||||||
"minimist": "^1.1.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",
|
"react-redux": "^2.0.0",
|
||||||
|
|
Loading…
Reference in New Issue