mirror of
https://github.com/HeyPuter/puter
synced 2024-11-14 22:06:00 +00:00
Merge pull request #490 from HeyPuter/customizable-menubar
Customizable menubar
This commit is contained in:
commit
a521ff3d7c
12
src/IPC.js
12
src/IPC.js
@ -475,8 +475,16 @@ window.addEventListener('message', async (event) => {
|
|||||||
const value = hydrator.hydrate(event.data.value);
|
const value = hydrator.hydrate(event.data.value);
|
||||||
|
|
||||||
// Show menubar
|
// Show menubar
|
||||||
const $menubar = $(el_window).find('.window-menubar')
|
let $menubar;
|
||||||
$menubar.show();
|
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
|
// disable system context menu
|
||||||
$menubar.on('contextmenu', (e) => {
|
$menubar.on('contextmenu', (e) => {
|
||||||
|
@ -27,18 +27,48 @@ export default {
|
|||||||
html: () => {
|
html: () => {
|
||||||
return `
|
return `
|
||||||
<h1>${i18n('personalization')}</h1>
|
<h1>${i18n('personalization')}</h1>
|
||||||
|
<div class="settings-card">
|
||||||
|
<strong>${i18n('background')}</strong>
|
||||||
|
<div style="flex-grow:1;">
|
||||||
|
<button class="button change-background" style="float:right;">${i18n('change_desktop_background')}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="settings-card">
|
<div class="settings-card">
|
||||||
<strong>${i18n('ui_colors')}</strong>
|
<strong>${i18n('ui_colors')}</strong>
|
||||||
<div style="flex-grow:1;">
|
<div style="flex-grow:1;">
|
||||||
<button class="button change-ui-colors" style="float:right;">${i18n('change_ui_colors')}</button>
|
<button class="button change-ui-colors" style="float:right;">${i18n('change_ui_colors')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-card">
|
<div class="settings-card" style="display: block; height: auto;">
|
||||||
<strong>${i18n('background')}</strong>
|
<strong>${i18n('menubar_style')}</strong>
|
||||||
<div style="flex-grow:1;">
|
<div style="flex-grow:1; margin-top: 10px;">
|
||||||
<button class="button change-background" style="float:right;">${i18n('change_desktop_background')}</button>
|
<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>
|
||||||
</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>
|
||||||
|
|
||||||
|
`;
|
||||||
},
|
},
|
||||||
init: ($el_window) => {
|
init: ($el_window) => {
|
||||||
$el_window.find('.change-ui-colors').on('click', function (e) {
|
$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');
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -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
|
// Remove `?ref=...` from navbar URL
|
||||||
if(window.url_query_params.has('ref')){
|
if(window.url_query_params.has('ref')){
|
||||||
window.history.pushState(null, document.title, '/');
|
window.history.pushState(null, document.title, '/');
|
||||||
@ -955,6 +978,7 @@ async function UIDesktop(options){
|
|||||||
ht += `<div class="toolbar" style="height:${window.toolbar_height}px;">`;
|
ht += `<div class="toolbar" style="height:${window.toolbar_height}px;">`;
|
||||||
// logo
|
// 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>`;
|
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
|
// 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 += `<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>`;
|
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){
|
$(el_desktop).on('click', function(e){
|
||||||
// blur all windows
|
// blur all windows
|
||||||
$('.window-active').removeClass('window-active');
|
$('.window-active').removeClass('window-active');
|
||||||
|
// hide all global menubars
|
||||||
|
$('.window-menubar-global').hide();
|
||||||
})
|
})
|
||||||
|
|
||||||
function display_ct() {
|
function display_ct() {
|
||||||
|
@ -275,9 +275,10 @@ async function UIWindow(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Menubar
|
// Menubar
|
||||||
{
|
if(window.menubar_style === 'window'){
|
||||||
h += `<div class="window-menubar">`;
|
h += `<div class="window-menubar" data-window-id="${win_id}"></div>`;
|
||||||
h += `</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
|
// Navbar
|
||||||
@ -3008,7 +3009,6 @@ $.fn.close = async function(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( this.on_before_exit ) {
|
if ( this.on_before_exit ) {
|
||||||
if ( ! await this.on_before_exit() ) return false;
|
if ( ! await this.on_before_exit() ) return false;
|
||||||
}
|
}
|
||||||
@ -3083,6 +3083,10 @@ $.fn.close = async function(options) {
|
|||||||
|
|
||||||
// remove backdrop
|
// remove backdrop
|
||||||
$(this).closest('.window-backdrop').remove();
|
$(this).closest('.window-backdrop').remove();
|
||||||
|
|
||||||
|
// remove global menubars
|
||||||
|
$(`.window-menubar-global[data-window-id="${win_id}"]`).remove();
|
||||||
|
|
||||||
// remove DOM element
|
// remove DOM element
|
||||||
if(options?.shrink_to_target){
|
if(options?.shrink_to_target){
|
||||||
// get target location
|
// get target location
|
||||||
@ -3316,6 +3320,7 @@ window.toggle_empty_folder_message = function(el_item_container){
|
|||||||
$.fn.focusWindow = function(event) {
|
$.fn.focusWindow = function(event) {
|
||||||
if(this.hasClass('window')){
|
if(this.hasClass('window')){
|
||||||
const $app_iframe = $(this).find('.window-app-iframe');
|
const $app_iframe = $(this).find('.window-app-iframe');
|
||||||
|
const win_id = $(this).attr('data-id');
|
||||||
$('.window').not(this).removeClass('window-active');
|
$('.window').not(this).removeClass('window-active');
|
||||||
$(this).addClass('window-active');
|
$(this).addClass('window-active');
|
||||||
// disable pointer events on all windows' iframes, except for this window's iframe
|
// 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);
|
$(`.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
|
// 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
|
// and to enable keyboard navigation through the menubar items
|
||||||
if($(event?.target).hasClass('window-menubar') || $(event?.target).closest('.window-menubar').length > 0){
|
if($(event?.target).hasClass('window-menubar') || $(event?.target).closest('.window-menubar').length > 0){
|
||||||
|
@ -802,6 +802,9 @@ span.header-sort-icon img {
|
|||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.window-menubar:not(.window-menubar-global):empty {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
.window-menubar {
|
.window-menubar {
|
||||||
display: flex;
|
display: flex;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -812,6 +815,22 @@ span.header-sort-icon img {
|
|||||||
padding: 2px 5px;
|
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 {
|
.window-menubar-item {
|
||||||
padding: calc(1.4 * var(--scale)) 0;
|
padding: calc(1.4 * var(--scale)) 0;
|
||||||
font-size: calc(5 * var(--scale));
|
font-size: calc(5 * var(--scale));
|
||||||
@ -825,11 +844,13 @@ span.header-sort-icon img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.window-menubar-item.active>span {
|
.window-menubar-item.active>span {
|
||||||
/* background-color: var(--select-color);
|
|
||||||
color: white; */
|
|
||||||
background-color: #e2e2e2;
|
background-color: #e2e2e2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.window-menubar-global .window-menubar-item.active>span {
|
||||||
|
background-color: #e4e4e43a;
|
||||||
|
}
|
||||||
|
|
||||||
.explorer-empty-message {
|
.explorer-empty-message {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
@ -1362,6 +1383,10 @@ span.header-sort-icon img {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menubar-style-desktop .window-app-iframe {
|
||||||
|
height: calc(100% + 35px);
|
||||||
|
}
|
||||||
|
|
||||||
.window-active .window-app-iframe {
|
.window-active .window-app-iframe {
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
|
@ -233,3 +233,10 @@ window.reset_item_positions = true; // The variable decides if the item position
|
|||||||
|
|
||||||
// default language
|
// 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';
|
@ -2397,3 +2397,19 @@ window.countSubstr = (str, substring)=>{
|
|||||||
|
|
||||||
return count;
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -147,6 +147,9 @@ const en = {
|
|||||||
log_out: 'Log Out',
|
log_out: 'Log Out',
|
||||||
looks_good: "Looks good!",
|
looks_good: "Looks good!",
|
||||||
manage_sessions: "Manage Sessions",
|
manage_sessions: "Manage Sessions",
|
||||||
|
menubar_style_desktop: "Desktop",
|
||||||
|
menubar_style_system: "System",
|
||||||
|
menubar_style_window: "Window",
|
||||||
move: 'Move',
|
move: 'Move',
|
||||||
moving_file: "Moving %%",
|
moving_file: "Moving %%",
|
||||||
my_websites: "My Websites",
|
my_websites: "My Websites",
|
||||||
|
Loading…
Reference in New Issue
Block a user