Browse Source

Improve the UX of the menubar and context menu

Nariman Jelveh 1 year ago
parent
commit
60f0ade3c1
3 changed files with 43 additions and 15 deletions
  1. 24 9
      src/IPC.js
  2. 14 2
      src/UI/UIContextMenu.js
  3. 5 4
      src/css/style.css

+ 24 - 9
src/IPC.js

@@ -30,7 +30,7 @@ import path from "./lib/path.js";
 import UIContextMenu from './UI/UIContextMenu.js';
 
 /**
- * In Puter, apps are loaded in iframes and communicate with the graphical user interface (GUI) aand each other using the postMessage API.
+ * In Puter, apps are loaded in iframes and communicate with the graphical user interface (GUI), and each other, using the postMessage API.
  * The following sets up an Inter-Process Messaging System between apps and the GUI that enables communication
  * for various tasks such as displaying alerts, prompts, managing windows, handling file operations, and more.
  * 
@@ -360,17 +360,20 @@ window.addEventListener('message', async (event) => {
     else if(event.data.msg === 'setMenubar') {
         const el_window = window.window_for_app_instance(event.data.appInstanceID);
 
-        console.error(`EXPERIMENTAL: setMenubar is a work-in-progress`);
         const hydrator = puter.util.rpc.getHydrator({
             target: target_iframe.contentWindow,
         });
         const value = hydrator.hydrate(event.data.value);
-        console.log('hydrated value', value);
 
         // Show menubar
         const $menubar = $(el_window).find('.window-menubar')
         $menubar.show();
 
+        // disable system context menu
+        $menubar.on('contextmenu', (e) => {
+            e.preventDefault();
+        });
+
         const sanitize_items = items => {
             return items.map(item => {
                 return {
@@ -405,7 +408,10 @@ window.addEventListener('message', async (event) => {
             const ctxMenu = UIContextMenu({
                 delay,
                 parent_element,
-                position: {top: pos.top + 28, left: pos.left},
+                position: {top: pos.top + 30, left: pos.left},
+                css: {
+                    'box-shadow': '0px 2px 6px #00000059'
+                },
                 items: sanitize_items(items),
             });
 
@@ -429,17 +435,15 @@ window.addEventListener('message', async (event) => {
                 const label = html_encode(item.label);
                 const el_item = $(`<div class="window-menubar-item"><span>${label}</span></div>`);
                 const parent_element = el_item.parent()[0];
-                el_item.on('click', () => {
+                
+                el_item.on('mousedown', (e) => {
                     if ( state_open ) {
                         state_open = false;
                         current && current.cancel({ meta: 'menubar' });
                         current_i = null;
                         current = null;
-                        return;
                     }
-                    if (item.action) {
-                        item.action();
-                    } else if (item.items) {
+                    if (item.items) {
                         const pos = el_item[0].getBoundingClientRect();
                         open_menu({
                             i,
@@ -447,8 +451,19 @@ window.addEventListener('message', async (event) => {
                             parent_element,
                             items: item.items,
                         });
+                        e.stopPropagation();
+                        e.preventDefault();
+                        return;
+                    }
+                })
+                
+                // Clicking an item with an action will trigger that action
+                el_item.on('click', () => {
+                    if (item.action) {
+                        item.action();
                     }
                 });
+
                 el_item.on('mouseover', () => {
                     if ( ! state_open ) return;
                     if ( ! item.items ) return;

+ 14 - 2
src/UI/UIContextMenu.js

@@ -124,11 +124,23 @@ function UIContextMenu(options){
         top: y_pos + "px",
         left: x_pos + "px"
     });
+
+    // Some times we need to apply custom CSS to the context menu
+    // This is different from the option flags for positioning and other basic styling
+    // This is for more advanced styling , like adding a border radius or a shadow that don't merit a new option
+    // Option flags should be reserved for essential styling that may have logic and sanitization attached to them
+    if(options.css){
+        $(contextMenu).css(options.css);
+    }
+
     // Show ContextMenu
-    if ( options?.delay === false ) {
+    if ( options?.delay === false) {
         $(contextMenu).show(0);
+    } else if(options?.delay === true || options?.delay === 1 || options?.delay === undefined) {
+        console.log('delay')
+        $(contextMenu).fadeIn(80).show(0);
     } else {
-        $(contextMenu).delay(100).show(0);
+        $(contextMenu).fadeIn(options?.delay).show(0);
     }
 
     // mark other context menus as inactive

+ 5 - 4
src/css/style.css

@@ -751,7 +751,7 @@ span.header-sort-icon img {
     border-bottom: 1px solid #e3e3e3;
     background-color: #fafafa;
     --scale: 2pt;
-    padding: 0 2pt;
+    padding: 2px 5px;
 }
 
 .window-menubar-item {
@@ -766,10 +766,10 @@ span.header-sort-icon img {
     border-radius: calc(1.5 * var(--scale));
 }
 
-.window-menubar-item:hover > span,
 .window-menubar-item.active > span {
-    background-color: var(--select-color);
-    color: white;
+    /* background-color: var(--select-color);
+    color: white; */
+    background-color: #e2e2e2;
 }
 
 .explorer-empty-message {
@@ -1454,6 +1454,7 @@ span.header-sort-icon img {
     min-width: 200px;
     background-color: rgba(231, 238, 245, .98);
     border: 1px solid #e4ebf3de;
+    border: 1px solid #CCC;
     box-shadow: 0px 0px 15px #00000066;
     padding-left: 6px;
     padding-right: 6px;