Merge branch 'feature/background-crossfade' into develop

This commit is contained in:
wpetit 2015-10-29 11:36:59 +01:00
commit 5348c30131
10 changed files with 517 additions and 113 deletions

View File

@ -13,13 +13,14 @@ html, body {
padding: 0; padding: 0;
margin: 0; margin: 0;
font-family: 'sawasdeeregular'; font-family: 'sawasdeeregular';
background-size: contain;
background-position: center;
background-color: rgb(34, 107, 160);
width: 100%; width: 100%;
height: 100%; height: 100%;
color: white; color: white;
overflow-x: hidden; overflow-x: hidden;
background: url('../img/background.svg');
background-size: cover;
background-repeat: no-repeat;
background-position: center;
} }
@ -34,7 +35,6 @@ html, body {
background-position: center center; background-position: center center;
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
transition: background-image 250ms ease-in-out;
} }
.full-width { .full-width {
@ -46,11 +46,6 @@ html, body {
.launcher { .launcher {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: url('../img/background.svg');
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
transition: background-image 250ms ease-in-out;
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
@ -58,6 +53,26 @@ html, body {
top: 0; top: 0;
} }
.launcher > .crossfade-image {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
}
.launcher .crossfade-image .top,
.launcher .crossfade-image .bottom {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
}
.launcher .main { .launcher .main {
flex-direction: row; flex-direction: row;
display: flex; display: flex;
@ -69,6 +84,7 @@ html, body {
align-items: center; align-items: center;
display: flex; display: flex;
width: 60px; width: 60px;
z-index: 10;
} }
.launcher .nav a.goback { .launcher .nav a.goback {
@ -306,6 +322,15 @@ html, body {
/* Animations */ /* Animations */
.crossfade-leave {
opacity: 1;
}
.crossfade-leave.crossfade-leave-active {
opacity: 0.01;
transition: opacity 500ms ease-in-out;
}
.pulse { .pulse {
-webkit-animation: 1s pulse infinite; -webkit-animation: 1s pulse infinite;
} }
@ -322,6 +347,13 @@ html, body {
100% { transform: scale(1); } 100% { transform: scale(1); }
} }
@-webkit-keyframes fade-out {
0% { opacity: 1; }
1% { opacity: 0.99; }
99% { opacity: 0.01; }
100% { opacity: 0; }
}
@-webkit-keyframes slide-in-left { @-webkit-keyframes slide-in-left {
0% { transform: translateX(-100%); } 0% { transform: translateX(-100%); }
100% { transform: translateX(0%); } 100% { transform: translateX(0%); }

334
eleve.json Normal file
View File

@ -0,0 +1,334 @@
{
"background": "./img/background2.jpg",
"items": [
{
"label": "Mathématiques",
"icon": "./icone-maths.png",
"items": [
{
"label": "À nous les nombres",
"icon": "chromium-browser",
"exec": "/usr/bin/anous"
},
{
"label": "Calcul mental",
"icon": "chromium-browser",
"exec": "/usr/bin/leterrier-calcul-mental"
},
{
"label": "Calculs",
"icon": "chromium-browser",
"exec": "/usr/bin/calculs"
},
{
"label": "Carmetal",
"icon": "chromium-browser",
"exec": "carmetal"
},
{
"label": "Kig",
"icon": "chromium-browser",
"exec": "kig"
},
{
"label": "Labyrinthe",
"icon": "chromium-browser",
"exec": "/usr/bin/labyrinthe"
},
{
"label": "OOo4Kids",
"icon": "chromium-browser",
"exec": "ooo4kids1.3 -math"
},
{
"label": "Opérations",
"icon": "chromium-browser",
"exec": "/usr/bin/operations"
},
{
"label": "TuxMath",
"icon": "chromium-browser",
"exec": "/usr/bin/tuxmath"
}
]
},
{
"label": "Français",
"icon": "./img/francais.png",
"items": [
{
"label": "Aller",
"icon": "chromium-browser",
"exec": "/usr/bin/aller"
},
{
"label": "Anki",
"icon": "chromium-browser",
"exec": "anki %f"
},
{
"label": "Dicorime",
"icon": "chromium-browser",
"exec": "dicorime"
},
{
"label": "Dictionnaire",
"icon": "chromium-browser",
"exec": "stardict"
},
{
"label": "GConjugo",
"icon": "chromium-browser",
"exec": "/usr/bin/gconjugo"
},
{
"label": "Kanagram",
"icon": "chromium-browser",
"exec": "kanagram"
},
{
"label": "Verbiste",
"icon": "chromium-browser",
"exec": "verbiste"
}
]
},
{
"label": "Histoire, géographie",
"icon": "./img/histoire-geo.png",
"items": [
{
"label": "KGeography",
"icon": "chromium-browser",
"exec": "kgeography"
}
]
},
{
"label": "Sciences",
"icon": "./img/sciences.png",
"items": [
{
"label": "Celestia",
"icon": "chromium-browser",
"exec": "celestia-gnome"
},
{
"label": "Kturtle",
"icon": "chromium-browser",
"exec": "kturtle"
},
{
"label": "Stellarium",
"icon": "chromium-browser",
"exec": "stellarium"
},
{
"label": "SunClock",
"icon": "chromium-browser",
"exec": "sunclock"
}
]
},
{
"label": "Autres matières",
"icon": "./img/divers.png",
"items": [
{
"label": "Childsplay",
"icon": "chromium-browser",
"exec": "/usr/games/childsplay"
},
{
"label": "GCompris",
"icon": "chromium-browser",
"exec": "/usr/games/gcompris"
},
{
"label": "GNU Solfege",
"icon": "chromium-browser",
"exec": "solfege"
},
{
"label": "Mulot",
"icon": "chromium-browser",
"exec": "/usr/bin/mulot"
},
{
"label": "MyPaint",
"icon": "chromium-browser",
"exec": "mypaint %f"
},
{
"label": "Omnitux",
"icon": "chromium-browser",
"exec": "/usr/bin/omnitux"
},
{
"label": "OOo4Kids Dessin",
"icon": "chromium-browser",
"exec": "ooo4kids1.3 -draw"
},
{
"label": "TuxPaint",
"icon": "chromium-browser",
"exec": "/usr/bin/tuxpaint"
},
{
"label": "TuxTyping",
"icon": "chromium-browser",
"exec": "/usr/games/tuxtype"
}
]
},
{
"label": "Internet & messagerie",
"icon": "./img/internet.png",
"items": [
{
"label": "Thunderbird",
"icon": "chromium-browser",
"exec": "/usr/bin/thunderbird"
},
{
"label": "Navigateur internet",
"icon": "firefox",
"exec": "/usr/bin/firefox"
}
]
},
{
"label": "Bureautique",
"icon": "./img/bureautique.png",
"items": [
{
"label": "LibreOffice Tableur",
"icon": "chromium-browser",
"exec": "/usr/bin/libreoffice --calc %U"
},
{
"label": "LibreOffice Texte",
"icon": "chromium-browser",
"exec": "/usr/bin/libreoffice --impress %U"
},
{
"label": "LibreOffice Présentation",
"icon": "chromium-browser",
"exec": "/usr/bin/libreoffice --impress %U"
},
{
"label": "Lecteur PDF",
"icon": "chromium-browser",
"exec": "/usr/bin/evince"
},
{
"label": "Diaporama",
"icon": "chromium-browser",
"exec": "ooo4kids1.3 -impress"
},
{
"label": "Tableau",
"icon": "chromium-browser",
"exec": "ooo4kids1.3 -calc"
},
{
"label": "Texte",
"icon": "chromium-browser",
"exec": "ooo4kids1.3 -writer"
}
]
},
{
"label": "Outils",
"icon": "./img/logoutil.png",
"items": [
{
"label": "Graveur de CD-DVD",
"icon": "chromium-browser",
"exec": "brasero"
},
{
"label": "Capture d'écran",
"icon": "chromium-browser",
"exec": "gnome-screenshot --interactive"
},
{
"label": "Créateur de diagrammes",
"icon": "chromium-browser",
"exec": "dia"
},
{
"label": "Calculatrice",
"icon": "chromium-browser",
"exec": "gcalctool"
},
{
"label": "Enregistreur de son",
"icon": "chromium-browser",
"exec": "gnome-sound-recorder"
},
{
"label": "Éditeur d'images",
"icon": "chromium-browser",
"exec": "pinta"
},
{
"label": "Table de caractères",
"icon": "chromium-browser",
"exec": "gucharmap"
},
{
"label": "Lecteur Multimédia",
"icon": "chromium-browser",
"exec": "/usr/bin/vlc"
},
{
"label": "Montage Vidéo",
"icon": "chromium-browser",
"exec": "openshot %F"
},
{
"label": "Créer des DVD",
"icon": "chromium-browser",
"exec": "2ManDVD"
},
{
"label": "Éditeur audio",
"icon": "chromium-browser",
"exec": "audacity %F"
},
{
"label": "Créer des diaporamas",
"icon": "chromium-browser",
"exec": "imagination %F"
}
]
},
{
"label": "Dossiers personnels",
"icon": "./img/dossier.png",
"items": [
{
"label": "Documents",
"icon": "chromium-browser",
"exec": "/usr/bin/nautilus Documents/"
},
{
"label": "Images",
"icon": "chromium-browser",
"exec": "/usr/bin/nautilus Images/"
},
{
"label": "Musique",
"icon": "chromium-browser",
"exec": "/usr/bin/nautilus Musique/"
},
{
"label": "Vidéos",
"icon": "chromium-browser",
"exec": "/usr/bin/nautilus Vidéos/"
}
]
}
]
}

View File

@ -7,9 +7,9 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="50px" width="32.529999"
height="50px" height="37.5"
viewBox="0 0 100 100" viewBox="0 0 65.059998 75"
preserveAspectRatio="xMidYMid" preserveAspectRatio="xMidYMid"
class="uil-hourglass" class="uil-hourglass"
id="svg2" id="svg2"
@ -43,112 +43,47 @@
id="namedview30" id="namedview30"
showgrid="false" showgrid="false"
inkscape:zoom="13.350176" inkscape:zoom="13.350176"
inkscape:cx="-10.530194" inkscape:cx="-3.9872051"
inkscape:cy="27.889305" inkscape:cy="18.89309"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="g6" /> inkscape:current-layer="g6"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<rect <rect
x="0" x="-17.46875"
y="0" y="-13"
width="100" width="100"
height="100" height="100"
fill="none"
class="bk" class="bk"
id="rect4" /> id="rect4"
style="fill:none" />
<g <g
id="g6"> id="g6"
transform="translate(-17.46875,-13)">
<path <path
fill="none"
stroke="#ffffff"
stroke-width="5"
stroke-miterlimit="10" stroke-miterlimit="10"
d="M58.4,51.7c-0.9-0.9-1.4-2-1.4-2.3s0.5-0.4,1.4-1.4 C70.8,43.8,79.8,30.5,80,15.5H70H30H20c0.2,15,9.2,28.1,21.6,32.3c0.9,0.9,1.4,1.2,1.4,1.5s-0.5,1.6-1.4,2.5 C29.2,56.1,20.2,69.5,20,85.5h10h40h10C79.8,69.5,70.8,55.9,58.4,51.7z" d="M 58.4,51.7 C 57.5,50.8 57,49.7 57,49.4 57,49.1 57.5,49 58.4,48 70.8,43.8 79.8,30.5 80,15.5 H 70 30 20 c 0.2,15 9.2,28.1 21.6,32.3 0.9,0.9 1.4,1.2 1.4,1.5 0,0.3 -0.5,1.6 -1.4,2.5 C 29.2,56.1 20.2,69.5 20,85.5 H 30 70 80 C 79.8,69.5 70.8,55.9 58.4,51.7 z"
class="glass" class="glass"
id="path8" id="path8"
style="fill:#a4a4a4;fill-opacity:1" /> style="fill:#a4a4a4;fill-opacity:1;stroke:#ffffff;stroke-width:5;stroke-miterlimit:10"
<clipPath inkscape:connector-curvature="0" />
id="uil-hourglass-clip1">
<rect
x="15"
y="20"
width="70"
height="25"
class="clip"
id="rect11">
<animate
attributeName="height"
from="25"
to="0"
dur="1s"
repeatCount="indefinite"
vlaues="25;0;0"
keyTimes="0;0.5;1"
id="animate13" />
<animate
attributeName="y"
from="20"
to="45"
dur="1s"
repeatCount="indefinite"
vlaues="20;45;45"
keyTimes="0;0.5;1"
id="animate15" />
</rect>
</clipPath>
<clipPath
id="uil-hourglass-clip2">
<rect
x="15"
y="55"
width="70"
height="25"
class="clip"
id="rect18">
<animate
attributeName="height"
from="0"
to="25"
dur="1s"
repeatCount="indefinite"
vlaues="0;25;25"
keyTimes="0;0.5;1"
id="animate20" />
<animate
attributeName="y"
from="80"
to="55"
dur="1s"
repeatCount="indefinite"
vlaues="80;55;55"
keyTimes="0;0.5;1"
id="animate22" />
</rect>
</clipPath>
<path <path
d="M29,23c3.1,11.4,11.3,19.5,21,19.5S67.9,34.4,71,23H29z" d="m 29,23 c 3.1,11.4 11.3,19.5 21,19.5 9.7,0 17.9,-8.1 21,-19.5 H 29 z"
clip-path="url(#uil-hourglass-clip1)" clip-path="url(#uil-hourglass-clip1)"
fill="#d2d2d2"
class="sand" class="sand"
id="path24" id="path24"
style="fill:#ffffff;fill-opacity:1" /> style="fill:#ffffff;fill-opacity:1"
inkscape:connector-curvature="0" />
<path <path
d="M71.6,78c-3-11.6-11.5-20-21.5-20s-18.5,8.4-21.5,20H71.6z" d="M 71.6,78 C 68.6,66.4 60.1,58 50.1,58 40.1,58 31.6,66.4 28.6,78 h 43 z"
clip-path="url(#uil-hourglass-clip2)" clip-path="url(#uil-hourglass-clip2)"
fill="#d2d2d2"
class="sand" class="sand"
id="path26" id="path26"
style="fill:#ffffff;fill-opacity:1" /> style="fill:#ffffff;fill-opacity:1"
<animateTransform inkscape:connector-curvature="0" />
attributeName="transform"
type="rotate"
from="0 50 50"
to="180 50 50"
repeatCount="indefinite"
dur="1s"
values="0 50 50;0 50 50;180 50 50"
keyTimes="0;0.7;1"
id="animateTransform28" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -25,8 +25,10 @@
"glob": "^5.0.14", "glob": "^5.0.14",
"ini": "^1.3.4", "ini": "^1.3.4",
"lodash": "^3.10.1", "lodash": "^3.10.1",
"react": "^0.13.3", "react": "^0.14.0",
"react-addons-css-transition-group": "^0.14.0",
"react-dnd": "^1.1.5", "react-dnd": "^1.1.5",
"react-dom": "^0.14.0",
"react-redux": "^2.0.0", "react-redux": "^2.0.0",
"redux": "^2.0.0", "redux": "^2.0.0",
"redux-thunk": "^0.1.0" "redux-thunk": "^0.1.0"

View File

@ -1,4 +1,5 @@
var React = require('react'); var React = require('react');
var ReactDOM = require('react-dom');
var LauncherView = require('./components/launcher/launcher-view.js'); var LauncherView = require('./components/launcher/launcher-view.js');
var EditView = require('./components/edit/edit-view.js'); var EditView = require('./components/edit/edit-view.js');
var Provider = require('react-redux').Provider; var Provider = require('react-redux').Provider;
@ -34,9 +35,9 @@ function select(state) {
// Connect App to Redux store // Connect App to Redux store
App = connect(select)(App); App = connect(select)(App);
React.render( ReactDOM.render(
<Provider store={store}> <Provider store={store}>
{ function() { return <App />; } } <App />
</Provider> </Provider>
, ,
document.body document.body

View File

@ -0,0 +1,59 @@
/* jshint node: true */
var React = require('react');
var AnimateMixin = require('../mixins/animate');
var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
module.exports = React.createClass({
mixins: [AnimateMixin],
propTypes: {
src: React.PropTypes.string
},
getInitialState: function() {
return { currSrc: null, prevSrc: null };
},
componentWillReceiveProps: function(nextProps) {
this.setState({ nextSrc: nextProps.src, currSrc: this.state.currSrc });
},
render: function() {
var topStyle = {
backgroundImage: 'url('+this.state.currSrc+')'
};
var bottomStyle = {
backgroundImage: 'url('+this.state.nextSrc+')',
};
var bottom = this.state.nextSrc ?
<div key={this.state.nextSrc} className="bottom" style={bottomStyle}></div> :
null
;
var top = this.state.currSrc ?
<div key={this.state.currSrc} className="top" style={topStyle}></div> :
null
;
return (
<div className="crossfade-image" {...this.props}>
{bottom}
<ReactCSSTransitionGroup transitionName="crossfade" transitionEnterTimeout={1000} transitionLeaveTimeout={1000}>
{top}
</ReactCSSTransitionGroup>
</div>
);
},
componentDidUpdate: function() {
if(this.state.nextSrc !== this.state.currSrc) {
this.setState({ currSrc: this.state.nextSrc });
}
}
});

View File

@ -1,4 +1,4 @@
var React = require('react/addons'); var React = require('react');
var classNames = require('classnames'); var classNames = require('classnames');
var AppIcon = require('../common/app-icon.js'); var AppIcon = require('../common/app-icon.js');
var DragSource = require('react-dnd').DragSource; var DragSource = require('react-dnd').DragSource;
@ -10,7 +10,7 @@ var TreeItem = React.createClass({
render: function() { render: function() {
var data = this.props.data; var data = this.props.data;
var connectDragSource = this.props.connectDragSource; var connectDragSource = this.props.connectDragSource;
var connectDropTarget = this.props.connectDropTarget; var connectDropTarget = this.props.connectDropTarget;

View File

@ -6,9 +6,11 @@ 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 CrossfadeImage = require('../common/crossfade-image');
var path = require('path'); var path = require('path');
var DEFAULT_PROFILE = path.join(__dirname, '..', '..', '..', 'default-profile.json'); var DEFAULT_PROFILE = path.join(__dirname, '..', '..', '..', 'default-profile.json');
var DEFAULT_BACKGROUND = path.join(__dirname, '..', '..', '..', 'img', 'background.svg');
var LauncherView = React.createClass({ var LauncherView = React.createClass({
@ -52,14 +54,11 @@ var LauncherView = React.createClass({
null null
; ;
var style = {}; var background = currentItem && currentItem.background ? currentItem.background : DEFAULT_BACKGROUND;
if(currentItem && currentItem.background) {
style.backgroundImage = 'url('+currentItem.background+')';
}
return ( return (
<div className="launcher" style={style}> <div className="launcher">
<CrossfadeImage src={background} />
{header} {header}
<div className="main"> <div className="main">
{nav} {nav}

View File

@ -1,5 +1,6 @@
var Events = { var Events = {
ANIMATION_END: 'webkitAnimationEnd' ANIMATION_END: 'webkitAnimationEnd',
TRANSITION_END: 'webkitTransitionEnd'
}; };
module.exports = { module.exports = {
@ -13,10 +14,51 @@ module.exports = {
el.style.webkitAnimation = animation; el.style.webkitAnimation = animation;
function onAnimEnd(evt) { function onAnimEnd(evt) {
el.style.webkitAnimation = '';
el.removeEventListener(Events.ANIMATION_END, onAnimEnd); el.removeEventListener(Events.ANIMATION_END, onAnimEnd);
return resolve(el); return resolve(el);
} }
});
},
transition: function(component, style, time, easing) {
return new Promise(function(resolve, reject) {
console.log('transition start', style, time);
time = time || '500ms';
easing = easing || 'linear';
var props = Object.keys(style);
var el = component.getDOMNode();
el.style.transition = null;
el.addEventListener(Events.TRANSITION_END, onTransitionEnd, false);
props.forEach(function(styleProp) {
el.style[styleProp] = style[styleProp].start;
});
var transition = '';
props.forEach(function(styleProp) {
if(transition) transition += ', ';
transition += styleProp + ' ' + time + ' ' + easing;
});
el.style.transition = transition;
props.forEach(function(styleProp) {
el.style[styleProp] = style[styleProp].end;
});
function onTransitionEnd(evt) {
console.log('transition end', evt);
el.style.transition = null;
el.removeEventListener(Events.TRANSITION_END, onTransitionEnd);
return resolve(el);
}
}); });
} }

View File

@ -1,4 +1,4 @@
var React = require('react'); var ReactDOM = require('react-dom');
var _listeners = []; var _listeners = [];
@ -6,7 +6,7 @@ module.exports = {
isInViewport: function() { isInViewport: function() {
var el = React.findDOMNode(this); var el = ReactDOM.findDOMNode(this);
if(!el) return false; if(!el) return false;