mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-28 04:11:32 +00:00
Remove settings UI & service; redirect to dashboard (#2900)
This commit is contained in:
@@ -1,117 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// About
|
||||
export default {
|
||||
id: 'about',
|
||||
title_i18n_key: 'about',
|
||||
icon: 'logo-outline.svg',
|
||||
html: () => {
|
||||
return `
|
||||
<div class="about-container">
|
||||
<div class="about">
|
||||
<a href="https://puter.com" target="_blank" class="logo"><img src="/images/logo.png"></a>
|
||||
<p class="description">${i18n('puter_description')}</p>
|
||||
<p class="links">
|
||||
<a href="mailto:hey@puter.com" target="_blank">hey@puter.com</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="https://docs.puter.com" target="_blank">${i18n('developers')}</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="https://status.puter.com" target="_blank">${i18n('status')}</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="https://puter.com/terms" target="_blank">${i18n('terms')}</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="https://puter.com/privacy" target="_blank">${i18n('privacy')}</a>
|
||||
<span style="color: #CCC;">•</span>
|
||||
<a href="#" class="show-credits">${i18n('credits')}</a>
|
||||
</p>
|
||||
<div class="social-links">
|
||||
<a href="https://twitter.com/HeyPuter/" target="_blank">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true" style="opacity: 0.7;"><g><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></g></svg>
|
||||
</a>
|
||||
<a href="https://github.com/HeyPuter/" target="_blank">
|
||||
<svg 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 fill-rule="evenodd" clip-rule="evenodd" fill="#5a606b" d="M24,0.6c-13.3,0-24,10.7-24,24c0,10.6,6.9,19.6,16.4,22.8 c1.2,0.2,1.6-0.5,1.6-1.2c0-0.6,0-2.1,0-4.1c-6.7,1.5-8.1-3.2-8.1-3.2c-1.1-2.8-2.7-3.5-2.7-3.5c-2.2-1.5,0.2-1.5,0.2-1.5 c2.4,0.2,3.7,2.5,3.7,2.5c2.1,3.7,5.6,2.6,7,2c0.2-1.6,0.8-2.6,1.5-3.2c-5.3-0.6-10.9-2.7-10.9-11.9c0-2.6,0.9-4.8,2.5-6.4 c-0.2-0.6-1.1-3,0.2-6.4c0,0,2-0.6,6.6,2.5c1.9-0.5,4-0.8,6-0.8c2,0,4.1,0.3,6,0.8c4.6-3.1,6.6-2.5,6.6-2.5c1.3,3.3,0.5,5.7,0.2,6.4 c1.5,1.7,2.5,3.8,2.5,6.4c0,9.2-5.6,11.2-11,11.8c0.9,0.7,1.6,2.2,1.6,4.4c0,3.2,0,5.8,0,6.6c0,0.6,0.4,1.4,1.7,1.2 C41.1,44.2,48,35.2,48,24.6C48,11.3,37.3,0.6,24,0.6z">
|
||||
</path>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://discord.gg/PQcx7Teh8u" target="_blank">
|
||||
<svg 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="M19.837,20.3a2.562,2.562,0,0,0,0,5.106,2.562,2.562,0,0,0,0-5.106Zm8.4,0a2.562,2.562,0,1,0,2.346,2.553A2.45,2.45,0,0,0,28.232,20.3Z" fill="#444444" data-color="color-2"></path> <path d="M39.41,1H8.59A4.854,4.854,0,0,0,4,6V37a4.482,4.482,0,0,0,4.59,4.572H34.672l-1.219-4.255L36.4,40.054,39.18,42.63,44,47V6A4.854,4.854,0,0,0,39.41,1ZM30.532,31.038s-.828-.989-1.518-1.863a7.258,7.258,0,0,0,4.163-2.737A13.162,13.162,0,0,1,30.532,27.8a15.138,15.138,0,0,1-3.335.989,16.112,16.112,0,0,1-5.957-.023,19.307,19.307,0,0,1-3.381-.989,13.112,13.112,0,0,1-2.622-1.357,7.153,7.153,0,0,0,4.025,2.714c-.69.874-1.541,1.909-1.541,1.909-5.083-.161-7.015-3.5-7.015-3.5a30.8,30.8,0,0,1,3.312-13.409,11.374,11.374,0,0,1,6.463-2.415l.23.276a15.517,15.517,0,0,0-6.049,3.013s.506-.276,1.357-.667a17.272,17.272,0,0,1,5.221-1.449,2.266,2.266,0,0,1,.391-.046,19.461,19.461,0,0,1,4.646-.046A18.749,18.749,0,0,1,33.2,15.007a15.307,15.307,0,0,0-5.727-2.921l.322-.368a11.374,11.374,0,0,1,6.463,2.415A30.8,30.8,0,0,1,37.57,27.542S35.615,30.877,30.532,31.038Z" fill="#444444"></path></g></svg> </a>
|
||||
<a href="https://www.linkedin.com/company/puter/" target="_blank">
|
||||
<svg 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 fill="#5a606b" d="M46,0H2C0.9,0,0,0.9,0,2v44c0,1.1,0.9,2,2,2h44c1.1,0,2-0.9,2-2V2C48,0.9,47.1,0,46,0z M14.2,40.9H7.1V18 h7.1V40.9z M10.7,14.9c-2.3,0-4.1-1.8-4.1-4.1c0-2.3,1.8-4.1,4.1-4.1c2.3,0,4.1,1.8,4.1,4.1C14.8,13,13,14.9,10.7,14.9z M40.9,40.9 h-7.1V29.8c0-2.7,0-6.1-3.7-6.1c-3.7,0-4.3,2.9-4.3,5.9v11.3h-7.1V18h6.8v3.1h0.1c0.9-1.8,3.3-3.7,6.7-3.7c7.2,0,8.5,4.7,8.5,10.9 V40.9z">
|
||||
</path>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version"></div>
|
||||
|
||||
<dialog class="credits">
|
||||
<div class="credit-content">
|
||||
<p style="margin: 0; font-size: 18px; text-align: center;">${i18n('oss_code_and_content')}</p>
|
||||
<div style="max-height: 300px; overflow-y: scroll;">
|
||||
<ul style="padding-left: 25px; padding-top:15px;">
|
||||
<li>FileSaver.js <a target="_blank" href="https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md">${i18n('license')}</a></li>
|
||||
<li>html-entities <a target="_blank" href="https://github.com/mdevils/html-entities/blob/master/LICENSE">${i18n('license')}</a></li>
|
||||
<li>iro.js <a target="_blank" href="https://github.com/jaames/iro.js/blob/master/LICENSE.txt">${i18n('license')}</a></li>
|
||||
<li>jQuery <a target="_blank" href="https://jquery.org/license/">${i18n('license')}</a></li>
|
||||
<li>jQuery-dragster <a target="_blank" href="https://github.com/catmanjan/jquery-dragster/blob/master/LICENSE">${i18n('license')}</a></li>
|
||||
<li>jQuery-menu-aim <a target="_blank" href="https://github.com/kamens/jQuery-menu-aim?tab=readme-ov-file#faq">${i18n('license')}</a></li>
|
||||
<li>jQuery UI <a target="_blank" href="https://jquery.org/license/">${i18n('license')}</a></li>
|
||||
<li>mime <a target="_blank" href="https://github.com/broofa/mime/blob/main/LICENSE">${i18n('license')}</a></li>
|
||||
<li>qrcodejs <a target="_blank" href="https://github.com/davidshimjs/qrcodejs/blob/master/LICENSE">${i18n('license')}</a></li>
|
||||
<li>Selection <a target="_blank" href="https://github.com/simonwep/selection/blob/master/LICENSE">${i18n('license')}</a></li>
|
||||
<li>socket.io <a target="_blank" href="https://github.com/socketio/socket.io/blob/main/LICENSE">${i18n('license')}</a></li>
|
||||
<li>Wallpaper by <a target="_blank" href="https://unsplash.com/@fakurian?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Milad Fakurian</a> on <a target="_blank" href="https://unsplash.com/photos/blue-orange-and-yellow-wallpaper-E8Ufcyxz514?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a></li>
|
||||
<li>Inter font by The Inter Project Authors <a target="_blank" href="https://github.com/rsms/inter">${i18n('license')}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
</div>`;
|
||||
},
|
||||
init: ($el_window) => {
|
||||
// server and version infomration
|
||||
puter.os.version()
|
||||
.then(res => {
|
||||
const deployed_date = new Date(res.deploy_timestamp).toLocaleString();
|
||||
$el_window.find('.version').html(`Version: ${html_encode(res.version)} • Server: ${html_encode(res.location)} • Deployed: ${html_encode(deployed_date)}`);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to fetch server info:', error);
|
||||
$el_window.find('.version').html('Failed to load version information.');
|
||||
});
|
||||
|
||||
$el_window.find('.credits').on('click', function (e) {
|
||||
if ( $(e.target).hasClass('credits') ) {
|
||||
$('.credits').get(0).close();
|
||||
}
|
||||
});
|
||||
|
||||
$el_window.find('.show-credits').on('click', function (e) {
|
||||
$('.credits').get(0).showModal();
|
||||
});
|
||||
|
||||
},
|
||||
};
|
||||
@@ -1,171 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import UIWindowChangePassword from '../UIWindowChangePassword.js';
|
||||
import UIWindowChangeEmail from './UIWindowChangeEmail.js';
|
||||
import UIWindowChangeUsername from '../UIWindowChangeUsername.js';
|
||||
import UIWindowConfirmUserDeletion from './UIWindowConfirmUserDeletion.js';
|
||||
import UIWindowManageSessions from '../UIWindowManageSessions.js';
|
||||
import UIWindow from '../UIWindow.js';
|
||||
|
||||
// About
|
||||
export default {
|
||||
id: 'account',
|
||||
title_i18n_key: 'account',
|
||||
icon: 'user.svg',
|
||||
html: () => {
|
||||
let h = '';
|
||||
// profile picture
|
||||
h += '<div style="overflow: visible; display: flex; margin-bottom: 20px; flex-direction: column; align-items: center;">';
|
||||
h += `<div class="profile-picture change-profile-picture" style="background-image: url('${html_encode(window.user?.profile?.picture ?? window.icons['profile.svg'])}');">`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
|
||||
// change password button
|
||||
if ( ! window.user.is_temp ) {
|
||||
h += '<div class="settings-card">';
|
||||
h += `<strong>${i18n('password')}</strong>`;
|
||||
h += '<div style="flex-grow:1;">';
|
||||
h += `<button class="button change-password" style="float:right;">${i18n('change_password')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
}
|
||||
|
||||
// change username button
|
||||
h += '<div class="settings-card">';
|
||||
h += '<div>';
|
||||
h += `<strong style="display:block;">${i18n('username')}</strong>`;
|
||||
h += `<span class="username" style="display:block; margin-top:5px;">${html_encode(window.user.username)}</span>`;
|
||||
h += '</div>';
|
||||
h += '<div style="flex-grow:1;">';
|
||||
h += `<button class="button change-username" style="float:right;">${i18n('change_username')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
// change email button
|
||||
if ( window.user.email ) {
|
||||
h += '<div class="settings-card">';
|
||||
h += '<div>';
|
||||
h += `<strong style="display:block;">${i18n('email')}</strong>`;
|
||||
h += `<span class="user-email" style="display:block; margin-top:5px;">${html_encode(window.user.email)}</span>`;
|
||||
h += '</div>';
|
||||
h += '<div style="flex-grow:1;">';
|
||||
h += `<button class="button change-email" style="float:right;">${i18n('change_email')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
}
|
||||
// 'Delete Account' button
|
||||
h += '<div class="settings-card settings-card-danger">';
|
||||
h += `<strong style="display: inline-block;">${i18n('delete_account')}</strong>`;
|
||||
h += '<div style="flex-grow:1;">';
|
||||
h += `<button class="button button-danger delete-account" style="float:right;">${i18n('delete_account')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
return h;
|
||||
},
|
||||
init: ($el_window) => {
|
||||
$el_window.find('.change-password').on('click', function (e) {
|
||||
UIWindowChangePassword({
|
||||
window_options: {
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
disable_parent_window: true,
|
||||
parent_center: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
$el_window.find('.change-username').on('click', function (e) {
|
||||
UIWindowChangeUsername({
|
||||
window_options: {
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
disable_parent_window: true,
|
||||
parent_center: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
$el_window.find('.change-email').on('click', function (e) {
|
||||
UIWindowChangeEmail({
|
||||
window_options: {
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
disable_parent_window: true,
|
||||
parent_center: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
$el_window.find('.manage-sessions').on('click', function (e) {
|
||||
UIWindowManageSessions({
|
||||
window_options: {
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
disable_parent_window: true,
|
||||
parent_center: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
$el_window.find('.delete-account').on('click', function (e) {
|
||||
UIWindowConfirmUserDeletion({
|
||||
window_options: {
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
disable_parent_window: true,
|
||||
parent_center: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
$el_window.find('.change-profile-picture').on('click', async function (e) {
|
||||
// open dialog
|
||||
UIWindow({
|
||||
path: `/${ window.user.username }/Desktop`,
|
||||
// this is the uuid of the window to which this dialog will return
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
allowed_file_types: ['.png', '.jpg', '.jpeg'],
|
||||
show_maximize_button: false,
|
||||
show_minimize_button: false,
|
||||
title: 'Open',
|
||||
is_dir: true,
|
||||
is_openFileDialog: true,
|
||||
selectable_body: false,
|
||||
});
|
||||
});
|
||||
$el_window.on('file_opened', async function (e) {
|
||||
let selected_file = Array.isArray(e.detail) ? e.detail[0] : e.detail;
|
||||
// set profile picture
|
||||
const profile_pic = await puter.fs.read(selected_file.path);
|
||||
// blob to base64
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(profile_pic);
|
||||
reader.onloadend = function () {
|
||||
// resizes the image to 150x150
|
||||
const img = new Image();
|
||||
img.src = reader.result;
|
||||
img.onload = function () {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = 150;
|
||||
canvas.height = 150;
|
||||
ctx.drawImage(img, 0, 0, 150, 150);
|
||||
const base64data = canvas.toDataURL('image/png');
|
||||
// update profile picture everywhere (matches helpers.js session refresh)
|
||||
$el_window.find('.profile-picture').css('background-image', `url(${ html_encode(base64data) })`);
|
||||
$('.profile-pic').css('background-image', `url(${ html_encode(base64data) })`);
|
||||
$('.profile-image').css('background-image', `url(${ html_encode(base64data) })`);
|
||||
$('.profile-image').addClass('profile-image-has-picture');
|
||||
// update profile picture
|
||||
update_profile(window.user.username, { picture: base64data });
|
||||
};
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -1,132 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const shortcutSections = () => ([
|
||||
{
|
||||
title: i18n('keyboard_shortcuts_general'),
|
||||
rows: [
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_open_help'),
|
||||
keys: 'F1 / Ctrl+?',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_search'),
|
||||
keys: 'Ctrl/Cmd + F',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_close_window'),
|
||||
keys: 'Ctrl + W',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_undo'),
|
||||
keys: 'Ctrl/Cmd + Z',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_select_all'),
|
||||
keys: 'Ctrl/Cmd + A',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_open_item'),
|
||||
keys: 'Enter',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_close_menus'),
|
||||
keys: 'Esc',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n('keyboard_shortcuts_navigation'),
|
||||
rows: [
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_arrow_navigation'),
|
||||
keys: 'Arrow Keys',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_type_to_select'),
|
||||
keys: i18n('keyboard_shortcuts_type_to_select_keys'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: i18n('keyboard_shortcuts_files'),
|
||||
rows: [
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_copy'),
|
||||
keys: 'Ctrl/Cmd + C',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_cut'),
|
||||
keys: 'Ctrl/Cmd + X',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_paste'),
|
||||
keys: 'Ctrl/Cmd + V',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_delete'),
|
||||
keys: 'Delete (Win/Linux) / Cmd + Backspace (Mac)',
|
||||
},
|
||||
{
|
||||
action: i18n('keyboard_shortcuts_permanent_delete'),
|
||||
keys: 'Shift + Delete (Win/Linux) / Option + Cmd + Backspace (Mac)',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
export default {
|
||||
id: 'keyboard-shortcuts',
|
||||
title_i18n_key: 'keyboard_shortcuts',
|
||||
icon: 'shortcut.svg',
|
||||
html: () => {
|
||||
const sections = shortcutSections();
|
||||
const sectionHtml = sections.map(section => {
|
||||
const rows = section.rows.map(row => `
|
||||
<tr>
|
||||
<td class="settings-shortcuts-action">${row.action}</td>
|
||||
<td class="settings-shortcuts-keys"><span>${row.keys}</span></td>
|
||||
</tr>
|
||||
`).join('');
|
||||
|
||||
return `
|
||||
<div class="settings-shortcuts-section">
|
||||
<h2>${section.title}</h2>
|
||||
<table class="settings-shortcuts-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>${i18n('keyboard_shortcuts_action')}</th>
|
||||
<th>${i18n('keyboard_shortcuts_shortcut')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${rows}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
return `
|
||||
<h1>${i18n('keyboard_shortcuts')}</h1>
|
||||
<p class="settings-shortcuts-intro">${i18n('keyboard_shortcuts_intro')}</p>
|
||||
${sectionHtml}
|
||||
`;
|
||||
},
|
||||
};
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import changeLanguage from '../../i18n/i18nChangeLanguage.js';
|
||||
|
||||
// About
|
||||
export default {
|
||||
id: 'language',
|
||||
title_i18n_key: 'language',
|
||||
icon: 'language.svg',
|
||||
html: () => {
|
||||
let h = `<h1>${i18n('language')}</h1>`;
|
||||
|
||||
// search
|
||||
h += `<div class="search-container" style="margin-bottom: 10px;">
|
||||
<input type="text" class="search search-language" placeholder="${i18n('search')}">
|
||||
</div>`;
|
||||
|
||||
// list of languages
|
||||
const available_languages = window.listSupportedLanguages();
|
||||
h += '<div class="language-list">';
|
||||
for ( let lang of available_languages ) {
|
||||
h += `<div class="language-item ${window.locale === lang.code ? 'active' : ''}" data-lang="${lang.code}" data-english-name="${html_encode(lang.english_name)}">${html_encode(lang.name)}<img class="checkmark" src="${window.icons['checkmark.svg']}"></div>`;
|
||||
}
|
||||
h += '</div>';
|
||||
return h;
|
||||
},
|
||||
init: ($el_window) => {
|
||||
$el_window.on('click', '.language-item', function () {
|
||||
const $this = $(this);
|
||||
const lang = $this.attr('data-lang');
|
||||
changeLanguage(lang);
|
||||
$this.siblings().removeClass('active');
|
||||
$this.addClass('active');
|
||||
// make sure all other language items are visible
|
||||
$this.closest('.language-list').find('.language-item').show();
|
||||
});
|
||||
|
||||
$el_window.on('input', '.search-language', function () {
|
||||
const $this = $(this);
|
||||
const search = $this.val().toLowerCase();
|
||||
const $container = $this.closest('.settings').find('.settings-content-container');
|
||||
const $content = $container.find('.settings-content.active');
|
||||
const $list = $content.find('.language-list');
|
||||
const $items = $list.find('.language-item');
|
||||
$items.each(function () {
|
||||
const $item = $(this);
|
||||
const lang = $item.attr('data-lang');
|
||||
const name = $item.text().toLowerCase();
|
||||
const english_name = $item.attr('data-english-name').toLowerCase();
|
||||
if ( name.includes(search) || lang.includes(search) || english_name.includes(search) ) {
|
||||
$item.show();
|
||||
} else {
|
||||
$item.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
on_show: ($content) => {
|
||||
// Focus on search
|
||||
$content.find('.search').first().focus();
|
||||
// make sure all language items are visible
|
||||
$content.find('.language-item').show();
|
||||
// empty search
|
||||
$content.find('.search').val('');
|
||||
},
|
||||
};
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import UIWindowThemeDialog from '../UIWindowThemeDialog.js';
|
||||
import UIWindowDesktopBGSettings from '../UIWindowDesktopBGSettings.js';
|
||||
|
||||
// About
|
||||
export default {
|
||||
id: 'personalization',
|
||||
title_i18n_key: 'personalization',
|
||||
icon: 'palette-outline.svg',
|
||||
html: () => {
|
||||
return `
|
||||
<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')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-card">
|
||||
<strong>${i18n('ui_colors')}</strong>
|
||||
<div style="flex-grow:1;">
|
||||
<button class="button change-ui-colors" style="float:right;">${i18n('change')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-card">
|
||||
<strong style="flex-grow:1;">${i18n('clock_visibility')}</strong>
|
||||
<select class="change-clock-visible" style="margin-left: 10px; max-width: 300px;">
|
||||
<option value="auto">${i18n('clock_visible_auto')}</option>
|
||||
<option value="hide">${i18n('clock_visible_hide')}</option>
|
||||
<option value="show">${i18n('clock_visible_show')}</option>
|
||||
</select>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
init: ($el_window) => {
|
||||
$el_window.find('.change-ui-colors').on('click', function (e) {
|
||||
UIWindowThemeDialog({
|
||||
window_options: {
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
disable_parent_window: true,
|
||||
parent_center: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
$el_window.find('.change-background').on('click', function (e) {
|
||||
UIWindowDesktopBGSettings({
|
||||
window_options: {
|
||||
parent_uuid: $el_window.attr('data-element_uuid'),
|
||||
disable_parent_window: true,
|
||||
parent_center: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
$el_window.on('change', 'select.change-clock-visible', function (e) {
|
||||
window.change_clock_visible(this.value);
|
||||
});
|
||||
|
||||
window.change_clock_visible();
|
||||
},
|
||||
};
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import UIWindow2FASetup from '../UIWindow2FASetup.js';
|
||||
import UIWindowDisable2FA from './UIWindowDisable2FA.js';
|
||||
|
||||
export default {
|
||||
id: 'security',
|
||||
title_i18n_key: 'security',
|
||||
icon: 'shield.svg',
|
||||
html: () => {
|
||||
let h = `<h1>${i18n('security')}</h1>`;
|
||||
let user = window.user;
|
||||
|
||||
// change password button
|
||||
if ( ! user.is_temp ) {
|
||||
h += '<div class="settings-card">';
|
||||
h += `<strong>${i18n('password')}</strong>`;
|
||||
h += '<div style="flex-grow:1;">';
|
||||
h += `<button class="button change-password" style="float:right;">${i18n('change_password')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
}
|
||||
|
||||
// session manager
|
||||
h += '<div class="settings-card">';
|
||||
h += `<strong>${i18n('sessions')}</strong>`;
|
||||
h += '<div style="flex-grow:1;">';
|
||||
h += `<button class="button manage-sessions" style="float:right;">${i18n('manage_sessions')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
|
||||
// configure 2FA
|
||||
if ( !user.is_temp && user.email_confirmed ) {
|
||||
h += `<div class="settings-card settings-card-security ${user.otp ? 'settings-card-success' : 'settings-card-warning'}">`;
|
||||
h += '<div>';
|
||||
h += `<strong style="display:block;">${i18n('two_factor')}</strong>`;
|
||||
h += `<span class="user-otp-state" style="display:block; margin-top:5px;">${
|
||||
i18n(user.otp ? 'two_factor_enabled' : 'two_factor_disabled')
|
||||
}</span>`;
|
||||
h += '</div>';
|
||||
h += '<div style="flex-grow:1;">';
|
||||
h += `<button class="button enable-2fa" style="float:right;${user.otp ? 'display:none;' : ''}">${i18n('enable_2fa')}</button>`;
|
||||
h += `<button class="button disable-2fa" style="float:right;${user.otp ? '' : 'display:none;'}">${i18n('disable_2fa')}</button>`;
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
}
|
||||
|
||||
return h;
|
||||
},
|
||||
init: ($el_window) => {
|
||||
$el_window.find('.enable-2fa').on('click', async function (e) {
|
||||
|
||||
const { promise } = await UIWindow2FASetup();
|
||||
const tfa_was_enabled = await promise;
|
||||
|
||||
if ( tfa_was_enabled ) {
|
||||
$el_window.find('.enable-2fa').hide();
|
||||
$el_window.find('.disable-2fa').show();
|
||||
$el_window.find('.user-otp-state').text(i18n('two_factor_enabled'));
|
||||
$el_window.find('.settings-card-security').removeClass('settings-card-warning');
|
||||
$el_window.find('.settings-card-security').addClass('settings-card-success');
|
||||
}
|
||||
|
||||
return;
|
||||
});
|
||||
|
||||
$el_window.find('.disable-2fa').on('click', async function (e) {
|
||||
const { promise } = await UIWindowDisable2FA();
|
||||
const tfa_was_disabled = await promise;
|
||||
|
||||
if ( tfa_was_disabled ) {
|
||||
$el_window.find('.enable-2fa').show();
|
||||
$el_window.find('.disable-2fa').hide();
|
||||
$el_window.find('.user-otp-state').text(i18n('two_factor_disabled'));
|
||||
$el_window.find('.settings-card-security').removeClass('settings-card-success');
|
||||
$el_window.find('.settings-card-security').addClass('settings-card-warning');
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -1,191 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Usage
|
||||
export default {
|
||||
id: 'usage',
|
||||
title_i18n_key: 'usage',
|
||||
icon: 'speedometer-outline.svg',
|
||||
html: () => {
|
||||
return `
|
||||
<h1>${i18n('usage')}<button class="update-usage-details" style="float:right;"><svg class="update-usage-details-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2z"/> <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466"/> </svg></button></h1>
|
||||
<div class="driver-usage">
|
||||
<div class="driver-usage-header">
|
||||
<h3 style="margin:0; font-size: 14px; flex-grow: 1; font-weight: 500;">${i18n('Storage')}</h3>
|
||||
<div style="font-size: 13px; margin-bottom: 3px; opacity:0.85;">
|
||||
<span id="storage-used"></span>
|
||||
<span> used of </span>
|
||||
<span id="storage-capacity"></span>
|
||||
<span id="storage-puter-used-w" style="display:none;"> (<span id="storage-puter-used"></span> ${i18n('storage_puter_used')})</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="storage-bar-wrapper">
|
||||
<span id="storage-used-percent"></span>
|
||||
<div id="storage-bar"></div>
|
||||
<div id="storage-bar-host"></div>
|
||||
</div>
|
||||
<div class="driver-usage-container" style="margin-top: 30px;">
|
||||
<div class="driver-usage-header">
|
||||
<h3 style="margin:0; font-size: 14px; flex-grow: 1; font-weight: 500;">${i18n('Resources')}</h3>
|
||||
<div style="font-size: 13px; margin-bottom: 3px; opacity:0.85;">
|
||||
<span id="total-usage"></span>
|
||||
<span> used of </span>
|
||||
<span id="total-capacity"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="usage-progbar-wrapper">
|
||||
<div class="usage-progbar" style="width: 0;">
|
||||
<span class="usage-progbar-percent"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="driver-usage-details" style="display:none; margin-top: 5px; font-size: 13px; cursor: pointer;">
|
||||
<div class="caret" style="float:left;"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-right-fill" viewBox="0 0 16 16"><path d="m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z"/></svg></div>
|
||||
<span class="driver-usage-details-text disable-user-select">View usage details</span>
|
||||
</div>
|
||||
<div class="driver-usage-details-content hide-scrollbar" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
init: ($el_window) => {
|
||||
update_usage_details($el_window);
|
||||
$($el_window).find('.update-usage-details').on('click', function () {
|
||||
update_usage_details($el_window);
|
||||
});
|
||||
|
||||
// Scoped click handler for usage details toggle
|
||||
$($el_window).on('click', '.driver-usage-details', function () {
|
||||
const $container = $(this).closest('.driver-usage');
|
||||
$container.find('.driver-usage-details-content').toggleClass('active');
|
||||
$(this).toggleClass('active');
|
||||
|
||||
// change the text of the driver-usage-details-text depending on the class
|
||||
if ( $(this).hasClass('active') ) {
|
||||
$(this).find('.driver-usage-details-text').text('Hide usage details');
|
||||
} else {
|
||||
$(this).find('.driver-usage-details-text').text('View usage details');
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
async function update_usage_details ($el_window) {
|
||||
// Add spinning animation and record start time
|
||||
const startTime = Date.now();
|
||||
$($el_window).find('.update-usage-details-icon').css('animation', 'spin 1s linear infinite');
|
||||
|
||||
const monthlyUsagePromise = puter.auth.getMonthlyUsage().then(res => {
|
||||
let monthlyAllowance = res.allowanceInfo?.monthUsageAllowance;
|
||||
let remaining = res.allowanceInfo?.remaining;
|
||||
let totalUsage = monthlyAllowance - remaining;
|
||||
let totalUsagePercentage = (totalUsage / monthlyAllowance * 100).toFixed(0);
|
||||
|
||||
$('#total-usage').html(window.number_format(totalUsage / 100_000_000, { decimals: 2, prefix: '$' }));
|
||||
$('#total-capacity').html(window.number_format(monthlyAllowance / 100_000_000, { decimals: 2, prefix: '$' }));
|
||||
$('.usage-progbar-percent').html(`${totalUsagePercentage }%`);
|
||||
$('.usage-progbar').css('width', `${totalUsagePercentage }%`);
|
||||
|
||||
// build the table for the usage details
|
||||
let h = '<table class="driver-usage-details-content-table">';
|
||||
|
||||
h += `<thead>
|
||||
<tr>
|
||||
<th>Resource</th>
|
||||
<th>Units</th>
|
||||
<th>Cost</th>
|
||||
</tr>
|
||||
</thead>`;
|
||||
|
||||
h += '<tbody>';
|
||||
for ( let key in res.usage ) {
|
||||
// value must be object
|
||||
if ( typeof res.usage[key] !== 'object' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the units
|
||||
let units = res.usage[key].units;
|
||||
|
||||
// Bytes should be formatted as human readable
|
||||
if ( key.startsWith('filesystem:') && key.endsWith(':bytes') ) {
|
||||
units = window.byte_format(units);
|
||||
}
|
||||
// Everything else should be formatted as a number
|
||||
else {
|
||||
units = window.number_format(units, { decimals: 0, thousandSeparator: ',' });
|
||||
}
|
||||
|
||||
h += `
|
||||
<tr>
|
||||
<td>${key}</td>
|
||||
<td>${units}</td>
|
||||
<td>${window.number_format(res.usage[key].cost / 100_000_000, { decimals: 2, prefix: '$' })}</td>
|
||||
</tr>`;
|
||||
}
|
||||
h += '</tbody>';
|
||||
h += '</table>';
|
||||
|
||||
$('.driver-usage-details-content').html(h);
|
||||
});
|
||||
|
||||
const spacePromise = puter.fs.space().then(res => {
|
||||
let usage_percentage = (res.used / res.capacity * 100).toFixed(0);
|
||||
usage_percentage = usage_percentage > 100 ? 100 : usage_percentage;
|
||||
|
||||
let general_used = res.used;
|
||||
|
||||
let host_usage_percentage = 0;
|
||||
if ( res.host_used ) {
|
||||
$('#storage-puter-used').html(window.byte_format(res.used));
|
||||
$('#storage-puter-used-w').show();
|
||||
|
||||
general_used = res.host_used;
|
||||
host_usage_percentage = ((res.host_used - res.used) / res.capacity * 100).toFixed(0);
|
||||
}
|
||||
|
||||
$('#storage-used').html(window.byte_format(general_used));
|
||||
$('#storage-capacity').html(window.byte_format(res.capacity));
|
||||
$('#storage-used-percent').html(
|
||||
`${usage_percentage }%${
|
||||
host_usage_percentage > 0
|
||||
? ` / ${ host_usage_percentage }%` : ''}`);
|
||||
$('#storage-bar').css('width', `${usage_percentage }%`);
|
||||
$('#storage-bar-host').css('width', `${host_usage_percentage }%`);
|
||||
if ( usage_percentage >= 100 ) {
|
||||
$('#storage-bar').css({
|
||||
'border-top-right-radius': '3px',
|
||||
'border-bottom-right-radius': '3px',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for both promises to complete
|
||||
await Promise.all([monthlyUsagePromise, spacePromise]);
|
||||
|
||||
// Ensure spinning continues for at least 1 second
|
||||
const elapsed = Date.now() - startTime;
|
||||
const minDuration = 1000; // 1 second
|
||||
if ( elapsed < minDuration ) {
|
||||
await new Promise(resolve => setTimeout(resolve, minDuration - elapsed));
|
||||
}
|
||||
|
||||
// Remove spinning animation
|
||||
$($el_window).find('.update-usage-details-icon').css('animation', '');
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Placeholder from '../../util/Placeholder.js';
|
||||
import UIWindow from '../UIWindow.js';
|
||||
|
||||
def(Symbol('TSettingsTab'), 'ui.traits.TSettingsTab');
|
||||
|
||||
async function UIWindowSettings (options) {
|
||||
return new Promise(async (resolve) => {
|
||||
options = options ?? {};
|
||||
|
||||
const svc_settings = globalThis.services.get('settings');
|
||||
|
||||
const tabs = svc_settings.get_tabs();
|
||||
const tab_placeholders = [];
|
||||
|
||||
let h = '';
|
||||
|
||||
h += '<div class="settings-container">';
|
||||
h += '<div class="settings">';
|
||||
// sidebar toggle
|
||||
h += '<button class="sidebar-toggle hidden-lg hidden-xl hidden-md"><div class="sidebar-toggle-button"><span></span><span></span><span></span></div></button>';
|
||||
// sidebar
|
||||
h += '<div class="settings-sidebar disable-user-select disable-context-menu">';
|
||||
// if data-is_fullpage="1" show title saying "Settings"
|
||||
if ( options.window_options?.is_fullpage ) {
|
||||
h += `<div class="settings-sidebar-title">${i18n('settings')}</div>`;
|
||||
}
|
||||
|
||||
// sidebar items
|
||||
h += `<div class="settings-sidebar-burger disable-context-menu disable-user-select" style="background-image: url(${window.icons['menu']});"></div>`;
|
||||
tabs.forEach((tab, i) => {
|
||||
h += `<div class="settings-sidebar-item disable-context-menu disable-user-select ${i === 0 ? 'active' : ''}" data-settings="${tab.id}" style="background-image: url(${window.icons[tab.icon]});">${i18n(tab.title_i18n_key)}</div>`;
|
||||
});
|
||||
h += '</div>';
|
||||
|
||||
// content
|
||||
h += '<div class="settings-content-container">';
|
||||
|
||||
tabs.forEach((tab, i) => {
|
||||
h += `<div class="settings-content ${i === 0 ? 'active' : ''}" data-settings="${tab.id}">`;
|
||||
if ( tab.factory || tab.dom ) {
|
||||
tab_placeholders[i] = Placeholder();
|
||||
h += tab_placeholders[i].html;
|
||||
} else {
|
||||
h += tab.html();
|
||||
}
|
||||
h += '</div>';
|
||||
});
|
||||
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
|
||||
const el_window = await UIWindow({
|
||||
title: 'Settings',
|
||||
app: 'settings',
|
||||
single_instance: true,
|
||||
icon: null,
|
||||
uid: null,
|
||||
is_dir: false,
|
||||
body_content: h,
|
||||
has_head: true,
|
||||
selectable_body: false,
|
||||
allow_context_menu: false,
|
||||
is_resizable: true,
|
||||
is_droppable: false,
|
||||
init_center: true,
|
||||
allow_native_ctxmenu: true,
|
||||
allow_user_select: true,
|
||||
backdrop: false,
|
||||
width: 800,
|
||||
height: 'auto',
|
||||
dominant: true,
|
||||
show_in_taskbar: false,
|
||||
draggable_body: false,
|
||||
onAppend: function (this_window) {
|
||||
// send event settings-window-opened
|
||||
window.dispatchEvent(new CustomEvent('settings-window-opened', { detail: { window: this_window } }));
|
||||
},
|
||||
window_class: 'window-settings',
|
||||
body_css: {
|
||||
width: 'initial',
|
||||
height: '100%',
|
||||
overflow: 'auto',
|
||||
},
|
||||
...options?.window_options ?? {},
|
||||
});
|
||||
const $el_window = $(el_window);
|
||||
tabs.forEach((tab, i) => {
|
||||
tab.init && tab.init($el_window);
|
||||
if ( tab.factory ) {
|
||||
const component = tab.factory();
|
||||
component.attach(tab_placeholders[i]);
|
||||
}
|
||||
if ( tab.reinitialize ) {
|
||||
tab.reinitialize();
|
||||
}
|
||||
if ( tab.dom ) {
|
||||
tab_placeholders[i].replaceWith(tab.dom);
|
||||
}
|
||||
});
|
||||
|
||||
// If options.tab is provided, open that tab
|
||||
if ( options.tab ) {
|
||||
const $tabToOpen = $el_window.find(`.settings-sidebar-item[data-settings="${options.tab}"]`);
|
||||
if ( $tabToOpen.length > 0 ) {
|
||||
setTimeout(() => {
|
||||
$tabToOpen.trigger('click');
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
$(el_window).on('click', '.settings-sidebar-item', function () {
|
||||
const $this = $(this);
|
||||
const settings = $this.attr('data-settings');
|
||||
const $container = $this.closest('.settings').find('.settings-content-container');
|
||||
const $content = $container.find(`.settings-content[data-settings="${settings}"]`);
|
||||
// add active class to sidebar item
|
||||
$this.siblings().removeClass('active');
|
||||
$this.addClass('active');
|
||||
// add active class to content
|
||||
$container.find('.settings-content').removeClass('active');
|
||||
$content.addClass('active');
|
||||
|
||||
// Run on_show handlers
|
||||
const tab = tabs.find((tab) => tab.id === settings);
|
||||
if ( tab?.on_show ) {
|
||||
tab.on_show($content);
|
||||
}
|
||||
});
|
||||
|
||||
resolve(el_window);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('mousedown', '.sidebar-toggle', function (e) {
|
||||
e.preventDefault();
|
||||
$('.settings-sidebar').toggleClass('active');
|
||||
$('.sidebar-toggle-button').toggleClass('active');
|
||||
// move sidebar toggle button
|
||||
setTimeout(() => {
|
||||
$('.sidebar-toggle').css({
|
||||
left: $('.settings-sidebar').hasClass('active') ? 243 : 2,
|
||||
});
|
||||
}, 10);
|
||||
});
|
||||
|
||||
$(document).on('click', '.settings-sidebar-item', function (e) {
|
||||
// hide sidebar
|
||||
$('.settings-sidebar').removeClass('active');
|
||||
// move sidebar toggle button ro the right
|
||||
setTimeout(() => {
|
||||
$('.sidebar-toggle').css({
|
||||
left: 2,
|
||||
});
|
||||
}, 10);
|
||||
|
||||
});
|
||||
|
||||
// clicking anywhere on the page will close the sidebar
|
||||
$(document).on('click', function (e) {
|
||||
// print event target class
|
||||
|
||||
if ( !$(e.target).closest('.settings-sidebar').length && !$(e.target).closest('.sidebar-toggle-button').length && !$(e.target).hasClass('sidebar-toggle-button') && !$(e.target).hasClass('sidebar-toggle') ) {
|
||||
$('.settings-sidebar').removeClass('active');
|
||||
$('.sidebar-toggle-button').removeClass('active');
|
||||
// move sidebar toggle button ro the right
|
||||
setTimeout(() => {
|
||||
$('.sidebar-toggle').css({
|
||||
left: 2,
|
||||
});
|
||||
}, 10);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
export default UIWindowSettings;
|
||||
@@ -35,7 +35,6 @@ import UITaskbar from './UITaskbar.js';
|
||||
import new_context_menu_item from '../helpers/new_context_menu_item.js';
|
||||
import refresh_item_container from '../helpers/refresh_item_container.js';
|
||||
import changeLanguage from '../i18n/i18nChangeLanguage.js';
|
||||
import UIWindowSettings from './Settings/UIWindowSettings.js';
|
||||
import UIWindowTaskManager from './UIWindowTaskManager.js';
|
||||
import truncate_filename from '../helpers/truncate_filename.js';
|
||||
import UINotification from './UINotification.js';
|
||||
@@ -1296,16 +1295,10 @@ async function UIDesktop (options) {
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------
|
||||
// /settings will open settings in fullpage mode
|
||||
// /settings redirects to /dashboard
|
||||
//--------------------------------------------------------------------------------------
|
||||
else if ( window.url_paths[0]?.toLocaleLowerCase() === 'settings' ) {
|
||||
// open settings
|
||||
UIWindowSettings({
|
||||
tab: window.url_paths[1] || 'about',
|
||||
window_options: {
|
||||
is_fullpage: true,
|
||||
},
|
||||
});
|
||||
window.open('/dashboard', '_blank');
|
||||
}
|
||||
// ---------------------------------------------
|
||||
// Run apps from insta-login URL
|
||||
@@ -2201,7 +2194,7 @@ $(document).on('click', '.user-options-menu-btn', async function (e) {
|
||||
html: i18n('keyboard_shortcuts'),
|
||||
id: 'keyboard_shortcuts',
|
||||
onClick: async function () {
|
||||
UIWindowSettings({ tab: 'keyboard-shortcuts' });
|
||||
window.open('/dashboard', '_blank');
|
||||
},
|
||||
},
|
||||
//--------------------------------------------------
|
||||
|
||||
@@ -48,7 +48,6 @@ import { IPCService } from './services/IPCService.js';
|
||||
import { LaunchOnInitService } from './services/LaunchOnInitService.js';
|
||||
import { LocaleService } from './services/LocaleService.js';
|
||||
import { ProcessService } from './services/ProcessService.js';
|
||||
import { SettingsService } from './services/SettingsService.js';
|
||||
import { ThemeService } from './services/ThemeService.js';
|
||||
import { privacy_aware_path } from './util/desktop.js';
|
||||
|
||||
@@ -92,7 +91,6 @@ const launch_services = async function (options) {
|
||||
register('theme', new ThemeService());
|
||||
register('process', new ProcessService());
|
||||
register('locale', new LocaleService());
|
||||
register('settings', new SettingsService());
|
||||
register('anti-csrf', new AntiCSRFService());
|
||||
register('__launch-on-init', new LaunchOnInitService());
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
import UIAlert from './UI/UIAlert.js';
|
||||
import UIWindowSearch from './UI/UIWindowSearch.js';
|
||||
import UIWindowSettings from './UI/Settings/UIWindowSettings.js';
|
||||
import launch_app from './helpers/launch_app.js';
|
||||
import open_item from './helpers/open_item.js';
|
||||
import determine_active_container_parent from './helpers/determine_active_container_parent.js';
|
||||
@@ -33,7 +32,7 @@ $(document).bind('keydown', async function (e) {
|
||||
if ( e.which === 112 || ((e.ctrlKey || e.metaKey) && e.shiftKey && e.which === 191) ) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
UIWindowSettings({ tab: 'keyboard-shortcuts' });
|
||||
window.open('/dashboard', '_blank');
|
||||
return false;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024-present Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter.
|
||||
*
|
||||
* Puter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Service } from '../definitions.js';
|
||||
|
||||
import AboutTab from '../UI/Settings/UITabAbout.js';
|
||||
import UsageTab from '../UI/Settings/UITabUsage.js';
|
||||
import AccountTab from '../UI/Settings/UITabAccount.js';
|
||||
import SecurityTab from '../UI/Settings/UITabSecurity.js';
|
||||
import PersonalizationTab from '../UI/Settings/UITabPersonalization.js';
|
||||
import LanguageTag from '../UI/Settings/UITabLanguage.js';
|
||||
import KeyboardShortcutsTab from '../UI/Settings/UITabKeyboardShortcuts.js';
|
||||
import UIElement from '../UI/UIElement.js';
|
||||
const TSettingsTab = use('ui.traits.TSettingsTab');
|
||||
|
||||
export class SettingsService extends Service {
|
||||
#tabs = [];
|
||||
async _init () {
|
||||
;[
|
||||
UsageTab,
|
||||
AccountTab,
|
||||
SecurityTab,
|
||||
PersonalizationTab,
|
||||
LanguageTag,
|
||||
KeyboardShortcutsTab,
|
||||
AboutTab,
|
||||
].forEach(tab => {
|
||||
this.register_tab(tab);
|
||||
});
|
||||
}
|
||||
get_tabs () {
|
||||
return this.#tabs;
|
||||
}
|
||||
register_tab (tab) {
|
||||
if ( tab instanceof UIElement ) {
|
||||
const ui_element = tab;
|
||||
tab = {
|
||||
...ui_element.as(TSettingsTab).get_metadata(),
|
||||
reinitialize () {
|
||||
ui_element.reinitialize();
|
||||
},
|
||||
get dom () {
|
||||
return ui_element.root;
|
||||
},
|
||||
};
|
||||
}
|
||||
this.#tabs.push(tab);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user