Sfoglia il codice sorgente

Merge pull request #490 from HeyPuter/customizable-menubar

Customizable menubar
Nariman Jelveh 11 mesi fa
parent
commit
a521ff3d7c

+ 10 - 2
src/IPC.js

@@ -475,8 +475,16 @@ window.addEventListener('message', async (event) => {
         const value = hydrator.hydrate(event.data.value);
 
         // Show menubar
-        const $menubar = $(el_window).find('.window-menubar')
-        $menubar.show();
+        let $menubar;
+        if(window.menubar_style === 'window')
+            $menubar = $(el_window).find('.window-menubar')
+        else{
+            $menubar = $('.window-menubar-global[data-window-id="'+$(el_window).attr('data-id')+'"]');
+            // hide all other menubars
+            $('.window-menubar-global').hide();
+        }
+        
+        $menubar.css('display', 'flex');
 
         // disable system context menu
         $menubar.on('contextmenu', (e) => {

+ 85 - 5
src/UI/Settings/UITabPersonalization.js

@@ -28,17 +28,47 @@ export default {
         return `
             <h1>${i18n('personalization')}</h1>
             <div class="settings-card">
-                <strong>${i18n('ui_colors')}</strong>
+                <strong>${i18n('background')}</strong>
                 <div style="flex-grow:1;">
-                    <button class="button change-ui-colors" style="float:right;">${i18n('change_ui_colors')}</button>
+                    <button class="button change-background" style="float:right;">${i18n('change_desktop_background')}</button>
                 </div>
             </div>
             <div class="settings-card">
-                <strong>${i18n('background')}</strong>
+                <strong>${i18n('ui_colors')}</strong>
                 <div style="flex-grow:1;">
-                    <button class="button change-background" style="float:right;">${i18n('change_desktop_background')}</button>
+                    <button class="button change-ui-colors" style="float:right;">${i18n('change_ui_colors')}</button>
+                </div>
+            </div>
+            <div class="settings-card" style="display: block; height: auto;">
+                <strong>${i18n('menubar_style')}</strong>
+                <div style="flex-grow:1; margin-top: 10px;">
+                    <div>
+                        <label style="display:inline;" for="menubar_style_system">
+                        <input type="radio" name="menubar_style" class="menubar_style" value="system" id="menubar_style_system">
+                        <strong>${i18n('menubar_style_system')}</strong>
+                        <p style="margin-left: 17px; margin-top: 5px; margin-bottom: 20px;">Set the menubar based on the host system settings</p>
+                        </label>
+                    </div>
+
+                    <div>
+                        <label style="display:inline;" for="menubar_style_desktop">
+                        <input type="radio" name="menubar_style" class="menubar_style" value="desktop" id="menubar_style_desktop">
+                        <strong>${i18n('menubar_style_desktop')}</strong>
+                        <p style="margin-left: 17px; margin-top: 5px; margin-bottom: 20px;">Show app menubar on in the desktop toolbar</p>
+                        </label>
+                    </div>
+
+                    <div>
+                        <label style="display:inline;" for="menubar_style_window">
+                        <input type="radio" name="menubar_style" class="menubar_style" value="window" id="menubar_style_window">
+                        <strong>${i18n('menubar_style_window')}</strong>
+                        <p style="margin-left: 17px; margin-top: 5px; margin-bottom: 20px;">Show app menubar on top of the app window</p>
+                        </label>
+                    </div>
                 </div>
-            </div>`;
+            </div>
+
+            `;
     },
     init: ($el_window) => {
         $el_window.find('.change-ui-colors').on('click', function (e) {
@@ -59,5 +89,55 @@ export default {
                 }
             });
         });
+
+        puter.kv.get('menubar_style').then(async (val) => {
+            if(val === 'system' || !val){
+                $el_window.find('#menubar_style_system').prop('checked', true);
+            }else if(val === 'desktop'){
+                $el_window.find('#menubar_style_desktop').prop('checked', true);
+            }
+            else if(val === 'window'){
+                $el_window.find('#menubar_style_window').prop('checked', true);
+            }
+        })
+
+        $el_window.find('.menubar_style').on('change', function (e) {
+            let value = $(this).val();
+            if(value === 'system' || value === 'desktop' || value === 'window'){
+                // save the new style to cloud kv
+                puter.kv.set('menubar_style', value);
+                
+                if(value === 'system'){
+                    if(detectHostOS() === 'macos')
+                        value = 'desktop';
+                    else
+                        value = 'window';
+                }
+                // apply the new style
+                if(value === 'desktop'){
+                    $('body').addClass('menubar-style-desktop');
+                    $('.window-menubar').each((_, el) => {
+                        $(el).insertAfter('.toolbar-puter-logo');
+                        // add window-menubar-global
+                        $(el).addClass('window-menubar-global');
+                        // hide
+                        $(el).hide();
+                    })
+                }else{
+                    $('body').removeClass('menubar-style-desktop');
+                    $('.window-menubar-global').each((_, el) => {
+                        let win_id = $(el).attr('data-window-id');
+                        $(el).insertAfter('.window[data-id="'+win_id+'"] .window-head');
+                        // remove window-menubar-global
+                        $(el).removeClass('window-menubar-global');
+                        // show
+                        $(el).css('display', 'flex');
+                    })
+                }
+                window.menubar_style = value;
+            }else{
+                console.error('Invalid menubar style value');
+            }
+        })
     },
 };

+ 26 - 0
src/UI/UIDesktop.js

@@ -562,6 +562,29 @@ async function UIDesktop(options){
         }
     })
 
+    // Get menubar style
+    puter.kv.get('menubar_style').then(async (val) => {
+        let value = val;
+        if(value === 'system' || value === 'desktop' || value === 'window'){
+            window.menubar_style = value;
+        }else{
+            window.menubar_style = 'system';
+        }
+
+        if(menubar_style === 'system'){
+            if(window.detectHostOS() === 'macos')
+                menubar_style = 'desktop';
+            else
+                menubar_style = 'window';
+        }
+
+        // set menubar style class to body
+        if(window.menubar_style === 'desktop'){
+            $('body').addClass('menubar-style-desktop');
+        }
+    })
+
+
     // Remove `?ref=...` from navbar URL
     if(window.url_query_params.has('ref')){
         window.history.pushState(null, document.title, '/');    
@@ -955,6 +978,7 @@ async function UIDesktop(options){
     ht += `<div class="toolbar"  style="height:${window.toolbar_height}px;">`;
         // logo
         ht += `<div class="toolbar-btn toolbar-puter-logo" title="Puter" style="margin-left: 10px; margin-right: auto;"><img src="${window.icons['logo-white.svg']}" draggable="false" style="display:block; width:17px; height:17px"></div>`;
+
         // create account button
         ht += `<div class="toolbar-btn user-options-create-account-btn ${window.user.is_temp ? '' : 'hidden' }" style="padding:0; opacity:1;" title="Save Account">`;
             ht += `<svg style="width: 17px; height: 17px;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48"><g transform="translate(0, 0)"><path d="M45.521,39.04L27.527,5.134c-1.021-1.948-3.427-2.699-5.375-1.679-.717,.376-1.303,.961-1.679,1.679L2.479,39.04c-.676,1.264-.635,2.791,.108,4.017,.716,1.207,2.017,1.946,3.42,1.943H41.993c1.403,.003,2.704-.736,3.42-1.943,.743-1.226,.784-2.753,.108-4.017ZM23.032,15h1.937c.565,0,1.017,.467,1,1.031l-.438,14c-.017,.54-.459,.969-1,.969h-1.062c-.54,0-.983-.429-1-.969l-.438-14c-.018-.564,.435-1.031,1-1.031Zm.968,25c-1.657,0-3-1.343-3-3s1.343-3,3-3,3,1.343,3,3-1.343,3-3,3Z" fill="#ffbb00"></path></g></svg>`;
@@ -1052,6 +1076,8 @@ async function UIDesktop(options){
     $(el_desktop).on('click', function(e){
         // blur all windows
         $('.window-active').removeClass('window-active');
+        // hide all global menubars
+        $('.window-menubar-global').hide();
     })  
 
     function display_ct() {

+ 14 - 4
src/UI/UIWindow.js

@@ -275,9 +275,10 @@ async function UIWindow(options) {
         }
 
         // Menubar
-        {
-            h += `<div class="window-menubar">`;
-            h += `</div>`;
+        if(window.menubar_style === 'window'){
+            h += `<div class="window-menubar" data-window-id="${win_id}"></div>`;
+        }else if(window.menubar_style === 'desktop'){
+            $('.toolbar-puter-logo').after(`<div class="window-menubar window-menubar-global" data-window-id="${win_id}"></div>`);
         }
 
         // Navbar
@@ -3008,7 +3009,6 @@ $.fn.close = async function(options) {
             }
         }
 
-
         if ( this.on_before_exit ) {
             if ( ! await this.on_before_exit() ) return false;
         }
@@ -3083,6 +3083,10 @@ $.fn.close = async function(options) {
 
             // remove backdrop
             $(this).closest('.window-backdrop').remove();
+
+            // remove global menubars
+            $(`.window-menubar-global[data-window-id="${win_id}"]`).remove();
+
             // remove DOM element
             if(options?.shrink_to_target){
                 // get target location
@@ -3316,6 +3320,7 @@ window.toggle_empty_folder_message = function(el_item_container){
 $.fn.focusWindow = function(event) {
     if(this.hasClass('window')){
         const $app_iframe = $(this).find('.window-app-iframe');
+        const win_id = $(this).attr('data-id');
         $('.window').not(this).removeClass('window-active');
         $(this).addClass('window-active');
         // disable pointer events on all windows' iframes, except for this window's iframe
@@ -3333,6 +3338,11 @@ $.fn.focusWindow = function(event) {
             $(`.window[data-parent_uuid="${$(this).attr('data-element_uuid')}"]`).css('z-index', ++window.last_window_zindex);
         }
 
+        // hide other global menubars
+        $('.window-menubar-global').not(`.window-menubar-global[data-window-id="${win_id}"]`).hide();
+        // show this window's global menubar
+        $(`.window-menubar-global[data-window-id="${win_id}"]`).show();
+
         // if a menubar or any of its items are clicked, don't focus the iframe. This is important to preserve the focus on the menubar
         // and to enable keyboard navigation through the menubar items
         if($(event?.target).hasClass('window-menubar') || $(event?.target).closest('.window-menubar').length > 0){

+ 27 - 2
src/css/style.css

@@ -802,6 +802,9 @@ span.header-sort-icon img {
     text-shadow: none;
 }
 
+.window-menubar:not(.window-menubar-global):empty {
+    display: none !important;
+}
 .window-menubar {
     display: flex;
     box-sizing: border-box;
@@ -812,6 +815,22 @@ span.header-sort-icon img {
     padding: 2px 5px;
 }
 
+.window-menubar-global{
+    background-color: transparent;
+    color: white;
+    border-bottom: none;
+    flex-grow: 1;
+    scale: 1;
+    --scale: 1;
+    margin-left: 15px;
+    padding: 0;
+}
+.window-menubar-global .window-menubar-item span{
+    padding: 3px 10px;
+    font-size: 13px;
+    border-radius: 3px;
+}
+
 .window-menubar-item {
     padding: calc(1.4 * var(--scale)) 0;
     font-size: calc(5 * var(--scale));
@@ -825,11 +844,13 @@ span.header-sort-icon img {
 }
 
 .window-menubar-item.active>span {
-    /* background-color: var(--select-color);
-    color: white; */
     background-color: #e2e2e2;
 }
 
+.window-menubar-global .window-menubar-item.active>span {
+    background-color: #e4e4e43a;
+}
+
 .explorer-empty-message {
     text-align: center;
     margin-top: 20px;
@@ -1362,6 +1383,10 @@ span.header-sort-icon img {
     overflow: hidden;
 }
 
+.menubar-style-desktop .window-app-iframe {
+    height: calc(100% + 35px);
+}
+
 .window-active .window-app-iframe {
     pointer-events: all;
 }

+ 8 - 1
src/globals.js

@@ -232,4 +232,11 @@ window.desktop_item_positions = {};
 window.reset_item_positions = true; // The variable decides if the item positions should be reset when the user enabled auto arrange
 
 // default language
-window.locale = 'en';
+window.locale = 'en';
+
+/* Menubar style
+ * 'window' - menubar is part of the window
+ * 'desktop' - menubar is part of the desktop
+ * 'system' - menubar is determined by the system (e.g. Windows, macOS)
+ */
+// window.menubar_style = 'desktop';

+ 16 - 0
src/helpers.js

@@ -2397,3 +2397,19 @@ window.countSubstr = (str, substring)=>{
 
     return count;
 }
+
+window.detectHostOS = function(){
+    var userAgent = window.navigator.userAgent;
+    var platform = window.navigator.platform;
+    var macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'];
+    var windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'];
+
+    if (macosPlatforms.indexOf(platform) !== -1) {
+        return 'macos';
+    } else if (windowsPlatforms.indexOf(platform) !== -1) {
+        return 'windows';
+    } else {
+        return 'other';
+    }
+}
+

+ 3 - 0
src/i18n/translations/en.js

@@ -147,6 +147,9 @@ const en = {
         log_out: 'Log Out',
         looks_good: "Looks good!",
         manage_sessions: "Manage Sessions",
+        menubar_style_desktop: "Desktop",
+        menubar_style_system: "System",
+        menubar_style_window: "Window",
         move: 'Move',
         moving_file: "Moving %%",
         my_websites: "My Websites",