From 5b1cec8789b22e8e436f9b86e3b5387db6354cd1 Mon Sep 17 00:00:00 2001 From: William Petit Date: Wed, 26 Aug 2015 17:53:46 +0200 Subject: [PATCH 1/2] Base categories --- css/style.css | 1 + default-profile.json | 18 +++++- index.html | 25 ++++++-- js/app.js | 141 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 162 insertions(+), 23 deletions(-) diff --git a/css/style.css b/css/style.css index b32143b..c4e93e9 100644 --- a/css/style.css +++ b/css/style.css @@ -43,6 +43,7 @@ li.app-item { transition: 150ms linear; position: relative; overflow: hidden; + min-width: 10%; } li.app-item::after { diff --git a/default-profile.json b/default-profile.json index 55345c0..0a8dc15 100644 --- a/default-profile.json +++ b/default-profile.json @@ -1,9 +1,21 @@ { "items": [ { - "label": "Chromium Browser", - "exec": "/usr/bin/chromium-browser", - "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png" + "label": "Root", + "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png", + "items": [ + { + "label": "Level 1", + "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png", + "items": [ + { + "label": "Chromium Browser", + "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png", + "exec": "/usr/bin/chromium-browser" + } + ] + } + ] } ] } diff --git a/index.html b/index.html index cc8e4f9..4d2e310 100644 --- a/index.html +++ b/index.html @@ -9,17 +9,32 @@
+ + + + + diff --git a/js/app.js b/js/app.js index 22f4644..b8f10e2 100644 --- a/js/app.js +++ b/js/app.js @@ -10,8 +10,12 @@ var gui = require('nw.gui'); var minimist = require('minimist'); - // Load templates - var itemsListTpl = Handlebars.compile(Pitaya.DOM.select('#items-list-tpl').innerHTML); + // Load templates... + var launcherViewTpl = Handlebars.compile(Pitaya.DOM.select('#launcher-view-tpl').innerHTML); + + // ... and partials + Handlebars.registerPartial('itemListTpl', Pitaya.DOM.select('#items-list-tpl').innerHTML); + Handlebars.registerPartial('itemTpl', Pitaya.DOM.select('#item-tpl').innerHTML); // Internal constants var DEFAULT_PROFILE = './default-profile.json'; @@ -34,6 +38,7 @@ .then(function() { return Pitaya; }) + .catch(Pitaya._onError) ; }; @@ -48,7 +53,7 @@ return Pitaya._loadJSONFile(profilePath) .then(function(profile) { Pitaya._profile = profile; - Pitaya.render(); + Pitaya.renderLauncherView(); return profile; }) ; @@ -59,10 +64,24 @@ * * @return Pitaya */ - Pitaya.render = function() { + Pitaya.renderLauncherView = function(currentItemPath) { + + console.log('render', currentItemPath); + + currentItemPath = Pitaya._normalizeItemPath(currentItemPath); var rootEl = Pitaya._rootEl; - var profile = Pitaya._profile; - rootEl.innerHTML = itemsListTpl(profile); + var currentItem = Pitaya._getItemByPath(currentItemPath); + + var data = { + currentItemPath: currentItemPath.join('.'), + currentItem: currentItem, + isRoot: currentItemPath.length === 0 + }; + + console.log('render data', data); + + rootEl.innerHTML = launcherViewTpl(data); + }; @@ -73,6 +92,7 @@ Pitaya._initListeners = function() { var rootEl = Pitaya._rootEl; rootEl.addEventListener('click', Pitaya._onItemClick); + rootEl.addEventListener('click', Pitaya._onGoBackClick); }; /** @@ -87,19 +107,105 @@ if( !appItemEl ) return; - var execPath = appItemEl.dataset.exec; + var itemPath = appItemEl.dataset.itemPath; + var item = Pitaya._getItemByPath(itemPath); - console.info('Launching application "'+execPath+'"...'); + console.log('item click',itemPath, item); - if(execPath) { - appItemEl.classList.add('loading'); - cp.exec(execPath, function(err) { - appItemEl.classList.remove('loading'); - if(err) return console.error(err.stack || err); - console.info('Application closed "'+execPath+'".'); - }); + if(!item) return; + + if('items' in item) { + return Pitaya.renderLauncherView(itemPath); } + if(item.exec) { + + console.info('Launching application "'+item.exec+'"...'); + appItemEl.classList.add('loading'); + + Pitaya._runApp(item.exec) + .then(function() { + appItemEl.classList.remove('loading'); + console.info('Application closed "'+item.exec+'".'); + }) + .catch(function(err) { + Pitaya._onError(err); + appItemEl.classList.remove('loading'); + }) + ; + + } + + }; + + /** + * GoBack button click handler + * @private + */ + Pitaya._onGoBackClick = function(evt) { + + var goBackEl = evt.srcElement.matches( '.goback') ? evt.srcElement : + Pitaya.DOM.getClosestAncestor(evt.srcElement, '.goback') + ; + + if(!goBackEl) return; + + var currentItemPath = goBackEl.dataset.itemPath; + var parentItemPath = Pitaya._normalizeItemPath(currentItemPath); + + parentItemPath.pop(); + + return Pitaya.renderLauncherView(parentItemPath); + + }; + + Pitaya._normalizeItemPath = function(itemPath) { + + if( Array.isArray(itemPath) ) return itemPath; + + if((typeof itemPath === 'string' && itemPath.length === 0) || !itemPath) return []; + + return itemPath.split('.').reduce(function(arr, index) { + if(index !== '') { + arr.push(+index); + } + return arr; + }, []); + + }; + + Pitaya._getItemByPath = function(itemPath, rootItem) { + + rootItem = rootItem || Pitaya._profile; + itemPath = Pitaya._normalizeItemPath(itemPath); + + var index = itemPath.slice(0,1)[0]; + + if(index === undefined) { + return rootItem; + } + + if(!('items' in rootItem)) { + return undefined; + } + + var subItem = rootItem.items[index]; + + if(itemPath.length === 0) { + return subItem; + } + + return Pitaya._getItemByPath(itemPath, subItem); + + }; + + Pitaya._runApp = function(execPath) { + return new Promise(function(resolve, reject) { + cp.exec(execPath, function(err) { + if(err) return reject(err); + return resolve(); + }); + }); }; /** @@ -123,4 +229,9 @@ }); }; + + Pitaya._onError = function(err) { + console.error(err.stack ? err.stack : err); + }; + }(window.Pitaya = window.Pitaya || {}, window)); From d6dad43b3f61564372cfb845883aaf1c61d539ac Mon Sep 17 00:00:00 2001 From: William Petit Date: Wed, 26 Aug 2015 20:17:18 +0200 Subject: [PATCH 2/2] =?UTF-8?q?Gestion=20d'un=20nombre=20arbitraire=20de?= =?UTF-8?q?=20sous=20cat=C3=A9gories=20+=20transitions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/style.css | 84 +++++++++++++++++++++++++++++++++++++------- default-profile.json | 21 +++++++++-- index.html | 16 +++++---- js/anim.js | 24 +++++++++++++ js/app.js | 37 ++++++++++--------- 5 files changed, 145 insertions(+), 37 deletions(-) create mode 100644 js/anim.js diff --git a/css/style.css b/css/style.css index c4e93e9..6739667 100644 --- a/css/style.css +++ b/css/style.css @@ -3,21 +3,51 @@ } html, body { - padding: 1Opx 10px; + padding: 0; margin: 0; font-family: 'Droid Sans', 'Ubuntu Sans', sans-serif; background: url('../img/background.png') no-repeat; background-size: contain; background-position: center; background-color: rgb(34, 107, 160); -} - -body, ul.apps-list { width: 100%; height: 100%; + color: white; + overflow-x: hidden; } -ul.apps-list { +/* Launcher View */ + +.launcher { + display: flex; + width: 100%; + height: 100%; + flex-direction: column; +} + +.launcher .category-header { + padding: 40px 50px 0; + font-size: 50px; +} + +.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 { + float: right; +} + +.launcher .category-header .goback { + font-weight: normal; +} + +.launcher ul.apps-list { display: block; margin: 0; padding: 0; @@ -28,10 +58,10 @@ ul.apps-list { justify-content: center; align-items: center; align-content: center; + flex-grow: 1; } -li.app-item { - background-color: red; +.launcher li.app-item { margin: 5px; border-radius: 5px; background-color: rgba(0,0,0,0.4); @@ -43,10 +73,10 @@ li.app-item { transition: 150ms linear; position: relative; overflow: hidden; - min-width: 10%; + min-width: 150px; } -li.app-item::after { +.launcher li.app-item::after { content: ' '; display: block; border-radius: 50%; @@ -58,22 +88,24 @@ li.app-item::after { top: -75%; } -li.app-item:hover { +.launcher li.app-item:hover { background-color: rgba(0,0,0,0.6); } -li.app-item > .app-icon { +.launcher li.app-item > .app-icon { width: 70%; height: auto; } -li.app-item > .app-label { +.launcher li.app-item > .app-label { display: block; text-align: center; color: white; } -li.app-item.loading { +/* Animations */ + +.pulse { -webkit-animation: 1s pulse infinite; } @@ -82,3 +114,29 @@ li.app-item.loading { 50% { transform: scale(1.1); } 100% { transform: scale(1); } } + +@-webkit-keyframes pulse-large { + 0% { transform: scale(1); } + 50% { transform: scale(1.5); } + 100% { transform: scale(1); } +} + +@-webkit-keyframes slide-in-left { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(0%); } +} + +@-webkit-keyframes slide-in-right { + 0% { transform: translateX(100%); } + 100% { transform: translateX(0%); } +} + +@-webkit-keyframes slide-out-left { + 0% { transform: translateX(0%); } + 100% { transform: translateX(-100%); } +} + +@-webkit-keyframes slide-out-right { + 0% { transform: translateX(0%); } + 100% { transform: translateX(100%); } +} diff --git a/default-profile.json b/default-profile.json index 0a8dc15..aa9154f 100644 --- a/default-profile.json +++ b/default-profile.json @@ -1,11 +1,11 @@ { "items": [ { - "label": "Root", + "label": "Level 1", "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png", "items": [ { - "label": "Level 1", + "label": "Level 2-1", "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png", "items": [ { @@ -14,6 +14,23 @@ "exec": "/usr/bin/chromium-browser" } ] + }, + { + "label": "Level 2-2", + "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png", + "items": [ + { + "label": "Level 3-1", + "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png", + "items": [ + { + "label": "Chromium Browser", + "icon": "/usr/share/icons/Mint-X/apps/48/chromium-browser.png", + "exec": "/usr/bin/chromium-browser" + } + ] + } + ] } ] } diff --git a/index.html b/index.html index 4d2e310..fc44a91 100644 --- a/index.html +++ b/index.html @@ -11,12 +11,15 @@ + diff --git a/js/anim.js b/js/anim.js new file mode 100644 index 0000000..44f700c --- /dev/null +++ b/js/anim.js @@ -0,0 +1,24 @@ +(function(Pitaya, window) { + + "use strict"; + + var Anim = Pitaya.Anim = {}; + var Events = Anim.Events = { + ANIMATION_END: 'webkitAnimationEnd' + }; + + Anim.play = function(el, animation) { + return new Promise(function(resolve, reject) { + + el.addEventListener(Events.ANIMATION_END, onAnimEnd, false); + el.style.webkitAnimation = animation; + + function onAnimEnd(evt) { + el.removeEventListener(Events.ANIMATION_END, onAnimEnd); + return resolve(el); + } + + }); + }; + +}(window.Pitaya = window.Pitaya || {}, window)); diff --git a/js/app.js b/js/app.js index b8f10e2..063fe35 100644 --- a/js/app.js +++ b/js/app.js @@ -66,8 +66,6 @@ */ Pitaya.renderLauncherView = function(currentItemPath) { - console.log('render', currentItemPath); - currentItemPath = Pitaya._normalizeItemPath(currentItemPath); var rootEl = Pitaya._rootEl; var currentItem = Pitaya._getItemByPath(currentItemPath); @@ -78,8 +76,6 @@ isRoot: currentItemPath.length === 0 }; - console.log('render data', data); - rootEl.innerHTML = launcherViewTpl(data); }; @@ -110,27 +106,30 @@ var itemPath = appItemEl.dataset.itemPath; var item = Pitaya._getItemByPath(itemPath); - console.log('item click',itemPath, item); - if(!item) return; if('items' in item) { - return Pitaya.renderLauncherView(itemPath); + var rootEl = Pitaya._rootEl; + Pitaya.Anim.play(rootEl, 'slide-out-left 250ms ease-in-out') + .then(function() { + Pitaya.renderLauncherView(itemPath); + return Pitaya.Anim.play(rootEl, 'slide-in-right 250ms ease-in-out'); + }) + ; } if(item.exec) { console.info('Launching application "'+item.exec+'"...'); - appItemEl.classList.add('loading'); + appItemEl.classList.add('pulse'); Pitaya._runApp(item.exec) .then(function() { - appItemEl.classList.remove('loading'); - console.info('Application closed "'+item.exec+'".'); + appItemEl.classList.remove('pulse'); }) .catch(function(err) { Pitaya._onError(err); - appItemEl.classList.remove('loading'); + appItemEl.classList.remove('pulse'); }) ; @@ -155,7 +154,13 @@ parentItemPath.pop(); - return Pitaya.renderLauncherView(parentItemPath); + var rootEl = Pitaya._rootEl; + Pitaya.Anim.play(rootEl, 'slide-out-right 250ms ease-in-out') + .then(function() { + Pitaya.renderLauncherView(parentItemPath); + return Pitaya.Anim.play(rootEl, 'slide-in-left 250ms ease-in-out'); + }) + ; }; @@ -179,9 +184,9 @@ rootItem = rootItem || Pitaya._profile; itemPath = Pitaya._normalizeItemPath(itemPath); - var index = itemPath.slice(0,1)[0]; + var itemIndex = itemPath[0]; - if(index === undefined) { + if(itemIndex === undefined) { return rootItem; } @@ -189,13 +194,13 @@ return undefined; } - var subItem = rootItem.items[index]; + var subItem = rootItem.items[itemIndex]; if(itemPath.length === 0) { return subItem; } - return Pitaya._getItemByPath(itemPath, subItem); + return Pitaya._getItemByPath(itemPath.slice(1), subItem); };