Skip to content

Commit 212bc88

Browse files
feat(gui): Add animation effects to the taskbar (#1365)
- Add new animation functionality to the taskbar; icons will enlarge when the mouse hovers over them - Introduce new CSS properties and styles to support the animation effects - Implement mouse move and leave event handling in UITaskbar - Add UITaskBarCreateCurve and UITask components
1 parent 1b1517d commit 212bc88

File tree

4 files changed

+222
-152
lines changed

4 files changed

+222
-152
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function baseCurve(x) {
2+
if (x < 0) return 0;
3+
if (x > 1) return 0;
4+
return Math.sin(x * Math.PI);
5+
}
6+
export function UITaskBarCreateCurve(totalXDis, topX, minY, maxY) {
7+
return function curve(x) {
8+
const beginX = topX - totalXDis / 2;
9+
const endX = topX + totalXDis / 2;
10+
if (x < beginX) return minY;
11+
if (x > endX) return minY;
12+
const yDis = maxY - minY;
13+
return baseCurve((x - beginX) / totalXDis) * yDis + minY;
14+
};
15+
}
16+
17+
export function UITaskBarLayout(items, curve) {
18+
for (const item of items) {
19+
const rect = item.getBoundingClientRect();
20+
const x = rect.x + rect.width / 2;
21+
const scale = curve(x);
22+
item.style.setProperty('--i', scale);
23+
}
24+
}

src/gui/src/UI/UITaskbar.js

Lines changed: 80 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,22 @@
77
* it under the terms of the GNU Affero General Public License as published
88
* by the Free Software Foundation, either version 3 of the License, or
99
* (at your option) any later version.
10-
*
10+
*
1111
* This program is distributed in the hope that it will be useful,
1212
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1313
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414
* GNU Affero General Public License for more details.
15-
*
15+
*
1616
* You should have received a copy of the GNU Affero General Public License
1717
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
*/
1919

2020
import UITaskbarItem from './UITaskbarItem.js'
2121
import UIPopover from './UIPopover.js'
2222
import launch_app from "../helpers/launch_app.js"
23+
import {UITaskBarCreateCurve, UITaskBarLayout} from './UITaskBarCreateCurve.js'
2324

24-
async function UITaskbar(options){
25+
async function UITaskbar(options) {
2526
window.global_element_id++;
2627

2728
options = options ?? {};
@@ -34,16 +35,18 @@ async function UITaskbar(options){
3435
async: true,
3536
contentType: "application/json",
3637
headers: {
37-
"Authorization": "Bearer "+window.auth_token
38+
"Authorization": "Bearer " + window.auth_token
3839
},
39-
success: function (apps){
40+
success: function (apps) {
4041
window.launch_apps = apps;
4142
}
4243
});
4344

4445
let h = '';
4546
h += `<div id="ui-taskbar_${window.global_element_id}" class="taskbar" style="height:${window.taskbar_height}px;">`;
46-
h += `<div class="taskbar-sortable" style="display: flex; justify-content: center; z-index: 99999;"></div>`;
47+
h += `<div class="taskbar-menu">`;
48+
h += `<div class="taskbar-sortable" style="display: flex; justify-content: center;align-items: flex-end; z-index: 99999;"></div>`;
49+
h += `</div>`;
4750
h += `</div>`;
4851

4952

@@ -59,9 +62,9 @@ async function UITaskbar(options){
5962
sortable: false,
6063
keep_in_taskbar: true,
6164
disable_context_menu: true,
62-
onClick: async function(item){
65+
onClick: async function (item) {
6366
// skip if popover already open
64-
if($(item).hasClass('has-open-popover'))
67+
if ($(item).hasClass('has-open-popover'))
6568
return;
6669

6770
// show popover
@@ -77,30 +80,30 @@ async function UITaskbar(options){
7780

7881
// In the rare case that launch_apps is not populated yet, get it from the server
7982
// then populate the popover
80-
if(!window.launch_apps || !window.launch_apps.recent || window.launch_apps.recent.length === 0){
83+
if (!window.launch_apps || !window.launch_apps.recent || window.launch_apps.recent.length === 0) {
8184
// get launch apps
8285
window.launch_apps = await $.ajax({
8386
url: window.api_origin + "/get-launch-apps?icon_size=64",
8487
type: 'GET',
8588
async: true,
8689
contentType: "application/json",
8790
headers: {
88-
"Authorization": "Bearer "+window.auth_token
91+
"Authorization": "Bearer " + window.auth_token
8992
},
9093
});
9194
}
92-
95+
9396
let apps_str = '';
9497

9598
apps_str += `<div class="launch-search-wrapper">`
96-
apps_str += `<input style="background-image:url('${window.icons['magnifier-outline.svg']}');" class="launch-search">`;
97-
apps_str += `<img class="launch-search-clear" src="${window.icons['close.svg']}">`;
99+
apps_str += `<input style="background-image:url('${window.icons['magnifier-outline.svg']}');" class="launch-search">`;
100+
apps_str += `<img class="launch-search-clear" src="${window.icons['close.svg']}">`;
98101
apps_str += `</div>`;
99102

100103
// -------------------------------------------
101104
// Recent apps
102105
// -------------------------------------------
103-
if(window.launch_apps.recent.length > 0){
106+
if (window.launch_apps.recent.length > 0) {
104107
// heading
105108
apps_str += `<h1 class="start-section-heading start-section-heading-recent">${i18n('recent')}</h1>`;
106109

@@ -109,29 +112,29 @@ async function UITaskbar(options){
109112
for (let index = 0; index < window.launch_recent_apps_count && index < window.launch_apps.recent.length; index++) {
110113
const app_info = window.launch_apps.recent[index];
111114
apps_str += `<div title="${html_encode(app_info.title)}" data-name="${html_encode(app_info.name)}" class="start-app-card">`;
112-
apps_str += `<div class="start-app" data-app-name="${html_encode(app_info.name)}" data-app-uuid="${html_encode(app_info.uuid)}" data-app-icon="${html_encode(app_info.icon)}" data-app-title="${html_encode(app_info.title)}">`;
113-
apps_str += `<img class="start-app-icon" src="${html_encode(app_info.icon ? app_info.icon : window.icons['app.svg'])}">`;
114-
apps_str += `<span class="start-app-title">${html_encode(app_info.title)}</span>`;
115-
apps_str += `</div>`;
115+
apps_str += `<div class="start-app" data-app-name="${html_encode(app_info.name)}" data-app-uuid="${html_encode(app_info.uuid)}" data-app-icon="${html_encode(app_info.icon)}" data-app-title="${html_encode(app_info.title)}">`;
116+
apps_str += `<img class="start-app-icon" src="${html_encode(app_info.icon ? app_info.icon : window.icons['app.svg'])}">`;
117+
apps_str += `<span class="start-app-title">${html_encode(app_info.title)}</span>`;
118+
apps_str += `</div>`;
116119
apps_str += `</div>`;
117120
}
118121
apps_str += `</div>`;
119122
}
120123
// -------------------------------------------
121124
// Reccomended apps
122125
// -------------------------------------------
123-
if(window.launch_apps.recommended.length > 0){
126+
if (window.launch_apps.recommended.length > 0) {
124127
// heading
125128
apps_str += `<h1 class="start-section-heading start-section-heading-recommended" style="${window.launch_apps.recent.length > 0 ? 'padding-top: 30px;' : ''}">${i18n('recommended')}</h1>`;
126129
// apps
127130
apps_str += `<div class="launch-apps-recommended">`;
128131
for (let index = 0; index < window.launch_apps.recommended.length; index++) {
129132
const app_info = window.launch_apps.recommended[index];
130133
apps_str += `<div title="${html_encode(app_info.title)}" data-name="${html_encode(app_info.name)}" class="start-app-card">`;
131-
apps_str += `<div class="start-app" data-app-name="${html_encode(app_info.name)}" data-app-uuid="${html_encode(app_info.uuid)}" data-app-icon="${html_encode(app_info.icon)}" data-app-title="${html_encode(app_info.title)}">`;
132-
apps_str += `<img class="start-app-icon" src="${html_encode(app_info.icon ? app_info.icon : window.icons['app.svg'])}">`;
133-
apps_str += `<span class="start-app-title">${html_encode(app_info.title)}</span>`;
134-
apps_str += `</div>`;
134+
apps_str += `<div class="start-app" data-app-name="${html_encode(app_info.name)}" data-app-uuid="${html_encode(app_info.uuid)}" data-app-icon="${html_encode(app_info.icon)}" data-app-title="${html_encode(app_info.title)}">`;
135+
apps_str += `<img class="start-app-icon" src="${html_encode(app_info.icon ? app_info.icon : window.icons['app.svg'])}">`;
136+
apps_str += `<span class="start-app-title">${html_encode(app_info.title)}</span>`;
137+
apps_str += `</div>`;
135138
apps_str += `</div>`;
136139
}
137140
apps_str += `</div>`;
@@ -141,7 +144,7 @@ async function UITaskbar(options){
141144
$(popover).find('.launch-popover').append(apps_str);
142145

143146
// focus on search input only if not on mobile
144-
if(!isMobile.phone)
147+
if (!isMobile.phone)
145148
$(popover).find('.launch-search').focus();
146149

147150
// make apps draggable
@@ -154,12 +157,12 @@ async function UITaskbar(options){
154157
distance: 5,
155158
revertDuration: 100,
156159
helper: 'clone',
157-
cursorAt: { left: 18, top: 20 },
158-
start: function(event, ui){
160+
cursorAt: {left: 18, top: 20},
161+
start: function (event, ui) {
159162
},
160-
drag: function(event, ui){
163+
drag: function (event, ui) {
161164
},
162-
stop: function(){
165+
stop: function () {
163166
}
164167
});
165168
}
@@ -175,11 +178,11 @@ async function UITaskbar(options){
175178
sortable: false,
176179
keep_in_taskbar: true,
177180
lock_keep_in_taskbar: true,
178-
onClick: function(){
181+
onClick: function () {
179182
let open_window_count = parseInt($(`.taskbar-item[data-app="explorer"]`).attr('data-open-windows'));
180-
if(open_window_count === 0){
181-
launch_app({ name: 'explorer', path: window.home_path});
182-
}else{
183+
if (open_window_count === 0) {
184+
launch_app({name: 'explorer', path: window.home_path});
185+
} else {
183186
return false;
184187
}
185188
}
@@ -188,7 +191,7 @@ async function UITaskbar(options){
188191
//---------------------------------------------
189192
// Add other useful apps to the taskbar
190193
//---------------------------------------------
191-
if(window.user.taskbar_items && window.user.taskbar_items.length > 0){
194+
if (window.user.taskbar_items && window.user.taskbar_items.length > 0) {
192195
for (let index = 0; index < window.user.taskbar_items.length; index++) {
193196
const app_info = window.user.taskbar_items[index];
194197
// add taskbar item for each app
@@ -197,13 +200,13 @@ async function UITaskbar(options){
197200
app: app_info.name,
198201
name: app_info.title,
199202
keep_in_taskbar: true,
200-
onClick: function(){
203+
onClick: function () {
201204
let open_window_count = parseInt($(`.taskbar-item[data-app="${app_info.name}"]`).attr('data-open-windows'));
202-
if(open_window_count === 0){
205+
if (open_window_count === 0) {
203206
launch_app({
204207
name: app_info.name,
205-
})
206-
}else{
208+
})
209+
} else {
207210
return false;
208211
}
209212
}
@@ -215,7 +218,7 @@ async function UITaskbar(options){
215218
// add `Trash` to the taskbar
216219
//---------------------------------------------
217220
const trash = await puter.fs.stat(window.trash_path);
218-
if(window.socket){
221+
if (window.socket) {
219222
window.socket.emit('trash.is_empty', {is_empty: trash.is_empty});
220223
}
221224

@@ -226,23 +229,28 @@ async function UITaskbar(options){
226229
sortable: false,
227230
keep_in_taskbar: true,
228231
lock_keep_in_taskbar: true,
229-
onClick: function(){
232+
onClick: function () {
230233
let open_windows = $(`.window[data-path="${html_encode(window.trash_path)}"]`);
231-
if(open_windows.length === 0){
232-
launch_app({ name: 'explorer', path: window.trash_path});
233-
}else{
234+
if (open_windows.length === 0) {
235+
launch_app({name: 'explorer', path: window.trash_path});
236+
} else {
234237
open_windows.focusWindow();
235238
}
236239
},
237-
onItemsDrop: function(items){
240+
onItemsDrop: function (items) {
238241
window.move_items(items, window.trash_path);
239242
}
240243
})
241244

242245
window.make_taskbar_sortable();
246+
247+
//---------------------------------------------
248+
// Taskbar is Animation
249+
//---------------------------------------------
250+
window.taskbar_is_animation()
243251
}
244252

245-
window.make_taskbar_sortable = function(){
253+
window.make_taskbar_sortable = function () {
246254
//-------------------------------------------
247255
// Taskbar is sortable
248256
//-------------------------------------------
@@ -251,41 +259,41 @@ window.make_taskbar_sortable = function(){
251259
items: '.taskbar-item-sortable:not(.has-open-contextmenu)',
252260
cancel: '.has-open-contextmenu',
253261
placeholder: "taskbar-item-sortable-placeholder",
254-
helper : 'clone',
262+
helper: 'clone',
255263
distance: 5,
256264
revert: 10,
257-
receive: function(event, ui){
258-
if(!$(ui.item).hasClass('taskbar-item')){
265+
receive: function (event, ui) {
266+
if (!$(ui.item).hasClass('taskbar-item')) {
259267
// if app is already in taskbar, cancel
260-
if($(`.taskbar-item[data-app="${$(ui.item).attr('data-app-name')}"]`).length !== 0){
268+
if ($(`.taskbar-item[data-app="${$(ui.item).attr('data-app-name')}"]`).length !== 0) {
261269
$(this).sortable('cancel');
262270
$('.taskbar .start-app').remove();
263271
return;
264272
}
265273
}
266274
},
267-
update: function(event, ui){
268-
if(!$(ui.item).hasClass('taskbar-item')){
275+
update: function (event, ui) {
276+
if (!$(ui.item).hasClass('taskbar-item')) {
269277
// if app is already in taskbar, cancel
270-
if($(`.taskbar-item[data-app="${$(ui.item).attr('data-app-name')}"]`).length !== 0){
278+
if ($(`.taskbar-item[data-app="${$(ui.item).attr('data-app-name')}"]`).length !== 0) {
271279
$(this).sortable('cancel');
272280
$('.taskbar .start-app').remove();
273281
return;
274282
}
275-
283+
276284
let item = UITaskbarItem({
277285
icon: $(ui.item).attr('data-app-icon'),
278286
app: $(ui.item).attr('data-app-name'),
279287
name: $(ui.item).attr('data-app-title'),
280288
append_to_taskbar: false,
281289
keep_in_taskbar: true,
282-
onClick: function(){
290+
onClick: function () {
283291
let open_window_count = parseInt($(`.taskbar-item[data-app="${$(ui.item).attr('data-app-name')}"]`).attr('data-open-windows'));
284-
if(open_window_count === 0){
292+
if (open_window_count === 0) {
285293
launch_app({
286294
name: $(ui.item).attr('data-app-name'),
287-
})
288-
}else{
295+
})
296+
} else {
289297
return false;
290298
}
291299
}
@@ -297,11 +305,26 @@ window.make_taskbar_sortable = function(){
297305
window.update_taskbar();
298306
}
299307
// only proceed to update DB if the item sorted was a pinned item otherwise no point in updating the taskbar in DB
300-
else if($(ui.item).attr('data-keep-in-taskbar') === 'true'){
308+
else if ($(ui.item).attr('data-keep-in-taskbar') === 'true') {
301309
window.update_taskbar();
302310
}
303311
},
304312
});
305313
}
306314

315+
window.taskbar_is_animation = function () {
316+
const range = 300;
317+
const maxScale = 1.8;
318+
const items = $('.taskbar-item');
319+
const taskbar = $('.taskbar')
320+
taskbar.on('mousemove', function (e) {
321+
const curve = UITaskBarCreateCurve(range, e.clientX, 1, maxScale);
322+
console.log(curve, 'UITaskBarCreateCurve');
323+
UITaskBarLayout(items, curve)
324+
})
325+
taskbar.on("mouseleave", function () {
326+
UITaskBarLayout(items, () => 1);
327+
})
328+
}
329+
307330
export default UITaskbar;

0 commit comments

Comments
 (0)