First version of Settings

This commit is contained in:
Nariman Jelveh 2024-03-24 00:41:27 -07:00
parent c16b2e3e14
commit 3aab04a245
35 changed files with 772 additions and 13 deletions

View File

@ -0,0 +1,415 @@
/**
* Copyright (C) 2024 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 UIWindow from '../UIWindow.js'
import UIWindowChangePassword from '../UIWindowChangePassword.js'
// import UIWindowChangeEmail from './UIWindowChangeEmail.js'
// import UIWindowDeleteAccount from './UIWindowDeleteAccount.js'
import UIWindowChangeUsername from '../UIWindowChangeUsername.js'
import changeLanguage from "../../i18n/i18nchangeLanguage.js"
async function UIWindowSettings(options){
return new Promise(async (resolve) => {
options = options ?? {};
let h = '';
h += `<div class="settings-container">`;
h += `<div class="settings">`;
// side bar
h += `<div class="settings-sidebar disable-user-select">`;
h += `<div class="settings-sidebar-item disable-user-select active" data-settings="about" style="background-image: url(${icons['logo-outline.svg']});">${i18n('about')}</div>`;
h += `<div class="settings-sidebar-item disable-user-select" data-settings="usage" style="background-image: url(${icons['speedometer-outline.svg']});">${i18n('usage')}</div>`;
h += `<div class="settings-sidebar-item disable-user-select" data-settings="account" style="background-image: url(${icons['user.svg']});">${i18n('account')}</div>`;
h += `<div class="settings-sidebar-item disable-user-select" data-settings="language" style="background-image: url(${icons['language.svg']});">${i18n('language')}</div>`;
h += `</div>`;
// content
h += `<div class="settings-content-container">`;
// About
h += `<div class="settings-content active" data-settings="about">`;
h += `<div class="about-container">`
h += `<div class="about" style="text-align: center;">
<a href="https://puter.com" target="_blank" class="logo"><img src="/images/logo.png"></a>
<p class="description">Puter is a privacy-first personal cloud to keep all your files, apps, and games in one
secure place, accessible from anywhere at any time.</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">Developers</a>
<span style="color: #CCC;"></span>
<a href="https://status.puter.com" target="_blank">Status</a>
<span style="color: #CCC;"></span>
<a href="https://puter.com/terms" target="_blank">Terms</a>
<span style="color: #CCC;"></span>
<a href="https://puter.com/privacy" target="_blank">Privacy</a>
<span style="color: #CCC;"></span>
<a href="#" class="show-credits">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;">Open Source Software 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">license</a></li>
<li>html-entities <a target="_blank" href="https://github.com/mdevils/html-entities/blob/master/LICENSE">license</a></li>
<li>iro.js <a target="_blank" href="https://github.com/jaames/iro.js/blob/master/LICENSE.txt">license</a></li>
<li>jQuery <a target="_blank" href="https://jquery.org/license/">license</a></li>
<li>jQuery-dragster <a target="_blank" href="https://github.com/catmanjan/jquery-dragster/blob/master/LICENSE">license</a></li>
<li>jQuery UI <a target="_blank" href="https://jquery.org/license/">license</a></li>
<li>lodash <a target="_blank" href="https://lodash.com/license">license</a></li>
<li>mime <a target="_blank" href="https://github.com/broofa/mime/blob/main/LICENSE">license</a></li>
<li>qrcodejs <a target="_blank" href="https://github.com/davidshimjs/qrcodejs/blob/master/LICENSE">license</a></li>
<li>Selection <a target="_blank" href="https://github.com/simonwep/selection/blob/master/LICENSE">license</a></li>
<li>socket.io <a target="_blank" href="https://github.com/socketio/socket.io/blob/main/LICENSE">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>
</ul>
</div>
</div>
</dialog>
`;
h += `</div>`;
h += `</div>`;
// Usage
h += `<div class="settings-content" data-settings="usage">`;
h += `<h1>Usage</h1>`;
h += `<div class="driver-usage">
<h3 style="margin-bottom: 5px; font-size: 14px;">Storage Usage</h3>
<div style="font-size: 13px; margin-bottom: 3px;">
<span id="storage-used"></span>
<span> used of </span>
<span id="storage-capacity"></span>
</div>
<div id="storage-bar-wrapper">
<span id="storage-used-percent"></span>
<div id="storage-bar"></div>
</div>
</div>`
h += `</div>`;
// Account
h += `<div class="settings-content" data-settings="account">`;
h += `<h1>Account</h1>`;
// change password button
h += `<div class="settings-card">`;
h += `<strong>Password</strong>`;
h += `<div style="flex-grow:1;">`;
h += `<button class="button change-password" style="float:right;">Change Password</button>`;
h += `</div>`;
h += `</div>`;
// change email button
if(user.email){
h += `<div class="settings-card">`;
h += `<strong>${user.email}</strong>`;
h += `<div style="flex-grow:1;">`;
h += `<button class="button change-email" style="margin-bottom: 10px;">Change Email</button>`;
h += `</div>`;
h += `</div>`;
}
// change username button
h += `<div class="settings-card">`;
h += `<div>`;
h += `<strong style="display:block;">Username</strong>`;
h += `<span style="display:block; margin-top:5px;">${user.username}</span>`;
h += `</div>`;
h += `<div style="flex-grow:1;">`;
h += `<button class="button change-username" style="float:right;">Change Username</button>`;
h += `</div>`
h += `</div>`;
// delete account button
h += `<div class="settings-card settings-card-danger">`;
h += `<strong style="display: inline-block;">Delete Account</strong>`;
h += `<div style="flex-grow:1;">`;
h += `<button class="button button-danger delete-account" style="float:right;">Delete Account</button>`;
h += `</div>`;
h += `</div>`;
h += `</div>`;
// Language
h += `<div class="settings-content" data-settings="language">`;
h += `<h1>Language</h1>`;
// search
h += `<div class="search-container" style="margin-bottom: 10px;">`;
h += `<input type="text" class="search" placeholder="Search">`;
h += `</div>`;
// list of languages
const available_languages = 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)}">${lang.name}</div>`;
}
h += `</div>`;
h += `</div>`;
h += `</div>`;
h += `</div>`;
h += `</div>`;
h += ``;
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: false,
is_droppable: false,
init_center: true,
allow_native_ctxmenu: true,
allow_user_select: true,
backdrop: false,
width: 800,
height: 500,
height: 'auto',
dominant: true,
show_in_taskbar: false,
draggable_body: false,
onAppend: function(this_window){
},
window_class: 'window-settings',
body_css: {
width: 'initial',
height: '100%',
overflow: 'auto'
}
});
$.ajax({
url: api_origin + "/drivers/usage",
type: 'GET',
async: true,
contentType: "application/json",
headers: {
"Authorization": "Bearer " + auth_token
},
statusCode: {
401: function () {
logout();
},
},
success: function (res) {
let h = ''; // Initialize HTML string for driver usage bars
// Loop through user services
res.user.forEach(service => {
const { monthly_limit, monthly_usage } = service;
let usageDisplay = ``;
if (monthly_limit !== null) {
let usage_percentage = (monthly_usage / monthly_limit * 100).toFixed(0);
usage_percentage = usage_percentage > 100 ? 100 : usage_percentage; // Cap at 100%
usageDisplay = `
<div class="driver-usage" style="margin-bottom: 10px;">
<h3 style="margin-bottom: 5px; font-size: 14px;">${service.service['driver.interface']} (${service.service['driver.method']}):</h3>
<span style="font-size: 13px; margin-bottom: 3px;">${monthly_usage} used of ${monthly_limit}</span>
<div class="usage-progbar-wrapper" style="width: 100%;">
<div class="usage-progbar" style="width: ${usage_percentage}%;"><span class="usage-progbar-percent">${usage_percentage}%</span></div>
</div>
</div>
`;
}
else {
usageDisplay = `
<div class="driver-usage" style="margin-bottom: 10px;">
<h3 style="margin-bottom: 5px; font-size: 14px;">${service.service['driver.interface']} (${service.service['driver.method']}):</h3>
<span style="font-size: 13px; margin-bottom: 3px;">Usage: ${monthly_usage} (Unlimited)</span>
</div>
`;
}
h += usageDisplay;
});
// Append driver usage bars to the container
$('.settings-content[data-settings="usage"]').append(`<div class="driver-usage-container">${h}</div>`);
}
})
// df
$.ajax({
url: api_origin + "/df",
type: 'GET',
async: true,
contentType: "application/json",
headers: {
"Authorization": "Bearer " + auth_token
},
statusCode: {
401: function () {
logout();
},
},
success: function (res) {
let usage_percentage = (res.used / res.capacity * 100).toFixed(0);
usage_percentage = usage_percentage > 100 ? 100 : usage_percentage;
$('#storage-used').html(byte_format(res.used));
$('#storage-capacity').html(byte_format(res.capacity));
$('#storage-used-percent').html(usage_percentage + '%');
$('#storage-bar').css('width', usage_percentage + '%');
if (usage_percentage >= 100) {
$('#storage-bar').css({
'border-top-right-radius': '3px',
'border-bottom-right-radius': '3px',
});
}
}
})
// version
$.ajax({
url: api_origin + "/version",
type: 'GET',
async: true,
contentType: "application/json",
headers: {
"Authorization": "Bearer " + auth_token
},
statusCode: {
401: function () {
logout();
},
},
success: function (res) {
var d = new Date(0);
$('.version').html('Version: ' + res.version + ' &bull; ' + 'Server: ' + res.location + ' &bull; ' + 'Deployed: ' + new Date(res.deploy_timestamp));
}
})
$(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();
})
$(el_window).find('.change-password').on('click', function (e) {
UIWindowChangePassword();
})
$(el_window).find('.change-email').on('click', function (e) {
UIWindowChangeEmail();
})
$(el_window).find('.delete-account').on('click', function (e) {
UIWindowDeleteAccount();
})
$(el_window).find('.change-username').on('click', function (e) {
UIWindowChangeUsername();
})
$(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');
// if language, focus on search
if(settings === 'language'){
$content.find('.search').first().focus();
// make sure all language items are visible
$content.find('.language-item').show();
// empty search
$content.find('.search').val('');
}
})
$(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', 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();
}
})
});
resolve(el_window);
});
}
export default UIWindowSettings

View File

@ -34,7 +34,8 @@ import UIWindowQR from "./UIWindowQR.js"
import UIWindowRefer from "./UIWindowRefer.js"
import UITaskbar from "./UITaskbar.js"
import new_context_menu_item from "../helpers/new_context_menu_item.js"
import ChangeLanguage from "../i18n/i18nChangeLanguage.js"
import changeLanguage from "../i18n/i18nchangeLanguage.js"
import UIWindowSettings from "./Settings/UIWindowSettings.js"
async function UIDesktop(options){
let h = '';
@ -1156,12 +1157,12 @@ $(document).on('click', '.user-options-menu-btn', async function(e){
// -------------------------------------------
// Load available languages
// -------------------------------------------
const supportedLanguagesItems = ListSupportedLanguages().map(lang => {
const supportedLanguagesItems = listSupportedLanguages().map(lang => {
return {
html: lang.name,
icon: window.locale === lang.code ? '✓' : '',
onClick: async function(){
ChangeLanguage(lang.code);
changeLanguage(lang.code);
}
}
});
@ -1288,10 +1289,7 @@ $(document).on('click', '.close-launch-popover', function(){
});
$(document).on('click', '.toolbar-puter-logo', function(){
// launch the about app
launch_app({name: 'about', window_options:{
single_instance: true,
}});
UIWindowSettings();
})
$(document).on('click', '.user-options-create-account-btn', async function(e){

View File

@ -2138,7 +2138,7 @@ label {
font: 14px "Helvetica Neue", Sans-Serif;
border: none !important;
backdrop-filter: blur(3px);
filter: drop-shadow(0 0 3px rgba(0,0,0,.455));
filter: drop-shadow(0 0 3px rgba(0, 0, 0, .455));
}
.arrow {
@ -3254,4 +3254,299 @@ label {
justify-content: center;
align-items: center;
display: none;
}
/*!
* ==================================================
* Settings
* ==================================================
*/
.settings-container{
display: flex;
flex-direction: column;
height: 100%;
}
.settings{
display: flex;
flex-direction: row;
-webkit-font-smoothing: antialiased;
flex-grow: 1;
}
.settings-sidebar{
width: 200px;
background-color: #f9f9f9;
border-right: 1px solid #e0e0e0;
padding: 20px;
}
.settings-sidebar-item{
cursor: pointer;
border-radius: 4px;
padding: 10px;
margin-bottom: 15px;
background-repeat: no-repeat;
background-position: 10px center;
background-size: 25px;
padding-left: 45px;
font-size: 15px;
}
.settings-sidebar-item:hover{
background-color: #e8e8e8;
}
.settings-sidebar-item.active{
background-color: #e0e0e0;
}
.settings-content-container{
flex: 1;
padding: 20px 30px;
height: 500px;
overflow-y: scroll;
}
.settings-content{
display: none;
}
.settings-content[data-settings="about"]{
height: 100%;
}
.settings-content h1{
font-size: 24px;
margin-bottom: 20px;
border-bottom: 1px solid #e0e0e0;
padding-bottom: 10px;
padding-left: 5px;
font-weight: 500;
}
.settings-content.active{
display: block;
}
.settings-content .about-container{
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.settings-content[data-settings="about"] a {
color: #1663d4;
text-decoration: none;
font-size: 12px;
}
.settings-content[data-settings="about"] a:hover {
text-decoration: underline;
}
.settings-content .logo,
.settings-content .logo img {
display: block;
width: 55px;
height: 55px;
margin: 0 auto;
border-radius: 4px;
}
.settings-content .links {
text-align: center;
font-size: 14px;
margin-top: 10px;
}
.settings-content .social-links {
text-align: center;
/* margin-top: 10px; */
}
.settings-content .social-links a {
opacity: 0.7;
transition: opacity 0.1s ease-in-out;
}
.settings-content .social-links a,
.settings-content .social-links a:hover {
text-decoration: none;
margin: 0 10px;
}
.settings-content .social-links a:hover {
opacity: 1;
}
.settings-content .social-links svg {
width: 20px;
height: 20px;
}
.settings-content .about {
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
padding: 20px 40px;
max-width: 500px;
}
.settings-content .version{
font-size: 9px;
color: #343c4f;
text-align: center;
margin-bottom: 10px;
opacity: 0.3;
transition: opacity 0.1s ease-in-out;
height: 12px;
}
.settings-content .version:hover{
opacity: 1;
}
.driver-usage {
background-color: white;
bottom: 0;
width: 100%;
box-sizing: border-box;
color: #3c4963;
height: 85px;
}
.credits{
padding: 0;
border: 1px solid #bfbfbf;
box-shadow: 1px 1px 10px 0px #8a8a8a;
width: 400px;
}
.credit-content a{
font-size:15px;
}
.credits .credit-content{
padding: 20px;
}
.credit-content{
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.credit-content ul{
max-height: 300px;
overflow-y: scroll;
background: #f4f4f4;
padding: 10px;
box-shadow: 2px 2px 5px 2px inset #CCC;
}
.credit-content li{
margin-bottom: 10px;
}
#storage-bar-wrapper {
width: 100%;
height: 15px;
border: 1px solid #8a9096;
border-radius: 3px;
background-color: #fff;
position: relative;
}
#storage-bar {
height: 15px;
background-color: #dbe3ef;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
width: 0;
}
#storage-used-percent {
position: absolute;
left: calc(50% - 20px);
text-align: center;
display: inline-block;
width: 40px;
font-size: 13px;
}
.usage-progbar-wrapper {
width: 100%;
height: 15px;
border: 1px solid #8a9096;
border-radius: 3px;
background-color: #fff;
position: relative;
}
.usage-progbar {
height: 15px;
background-color: #dbe3ef;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
width: 0;
}
.usage-progbar-percent {
position: absolute;
left: calc(50% - 20px);
text-align: center;
display: inline-block;
width: 40px;
font-size: 13px;
}
.version{
font-size: 9px;
color: #343c4f;
text-align: center;
margin-bottom: 10px;
opacity: 0.3;
transition: opacity 0.1s ease-in-out;
height: 12px;
}
.version:hover{
opacity: 1;
}
.language-list{
display: grid;
grid-template-columns: 33.333333333% 33.333333333% 33.333333333%;
}
.language-item{
cursor: pointer;
padding: 10px;
border-radius: 4px;
margin-bottom: 10px;
margin-right: 10px;
}
.language-item:hover{
background-color: #f6f6f6;
}
.language-item.active{
background-color: #e0e0e0;
}
.settings-card{
overflow: hidden;
padding: 10px 15px;
border: 1px solid;
border-radius: 4px;
background: #f7f7f7a1;
border: 1px solid #cccccc8f;
margin-bottom: 20px;
display: flex;
flex-direction: row;
align-items: center;
height: 45px;
}
.settings-card strong{
font-weight: 500;
}
.settings-card-danger{
border-color: #f0080866;
background: #ffecec;
color: rgb(215 2 2);
}

View File

@ -220,4 +220,7 @@ window.feature_flags = {
window.is_auto_arrange_enabled = true;
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
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';

View File

@ -722,7 +722,7 @@ window.mutate_user_preferences = function(user_preferences_delta) {
window.update_user_preferences = function(user_preferences) {
window.user_preferences = user_preferences;
localStorage.setItem('user_preferences', JSON.stringify(user_preferences));
window.locale = user_preferences.language;
window.locale = user_preferences.language ?? 'en';
}
window.sendWindowWillCloseMsg = function(iframe_element) {

View File

@ -18,7 +18,7 @@
*/
import translations from './translations/translations.js';
window.ListSupportedLanguages = () => Object.keys(translations).map(lang => translations[lang]);
window.listSupportedLanguages = () => Object.keys(translations).map(lang => translations[lang]);
window.i18n = function (key, replacements = [], encode_html = true) {
if(typeof replacements === 'boolean' && encode_html === undefined){

View File

@ -17,11 +17,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
function ChangeLanguage(lang) {
function changeLanguage(lang) {
window.locale = lang;
window.mutate_user_preferences({
language : lang,
});
}
export default ChangeLanguage;
export default changeLanguage;

View File

@ -18,6 +18,7 @@
*/
const ar = {
name: "العربية",
english_name: "Arabic",
code: "ar",
dictionary: {
access_granted_to: "دخول مسموح به",

View File

@ -18,6 +18,7 @@
*/
const bn = {
name: "বাংলা",
english_name: "Bengali",
code: "bn",
dictionary: {
access_granted_to: "অ্যাক্সেস মঞ্জুর করা হয়েছে",

View File

@ -18,6 +18,7 @@
*/
const da = {
name: "Dansk",
english_name: "Danish",
code: "da",
dictionary: {
access_granted_to: "Adgang givet til",

View File

@ -18,6 +18,7 @@
*/
const de = {
name: "Deutsch",
english_name: "German",
code: "de",
dictionary: {
access_granted_to: "Erlaubt zugriff auf",

View File

@ -18,6 +18,7 @@
*/
const emoji = {
name: "🌍",
english_name: "Emoji",
code: "emoji",
dictionary: {
access_granted_to: "🔓✅",

View File

@ -18,8 +18,11 @@
*/
const en = {
name: "English",
english_name: "English",
code: "en",
dictionary: {
about: "About",
account: "Account",
access_granted_to: "Access Granted To",
add_existing_account: "Add Existing Account",
all_fields_required: 'All fields are required.',
@ -87,6 +90,7 @@ const en = {
items_in_trash_cannot_be_renamed: `This item can't be renamed because it's in the trash. To rename this item, first drag it out of the Trash.`,
jpeg_image: 'JPEG image',
keep_in_taskbar: 'Keep in Taskbar',
language: "Language",
loading: 'Loading',
log_in: "Log In",
log_into_another_account_anyway: 'Log into another account anyway',
@ -173,6 +177,7 @@ const en = {
unzip: "Unzip",
upload: 'Upload',
upload_here: 'Upload here',
usage: 'Usage',
username: "Username",
username_changed: 'Username updated successfully.',
versions: "Versions",

View File

@ -18,6 +18,7 @@
*/
const es = {
name: "Español",
english_name: "Spanish",
code: "es",
dictionary: {
access_granted_to: "Acceso Permitido A",

View File

@ -18,6 +18,7 @@
*/
const fa = {
name: "فارسی",
english_name: "Farsi",
code: "fa",
dictionary: {
access_granted_to: "دسترسی داده شده به",

View File

@ -18,6 +18,7 @@
*/
const fi = {
name: "Suomi",
english_name: "Finnish",
code: "fi",
dictionary: {
access_granted_to: "Käyttöoikeus Myönnetty",

View File

@ -18,6 +18,7 @@
*/
const fr = {
name: "Français",
english_name: "French",
code: "fr",
dictionary: {
access_granted_to: "Accès accordé à",

View File

@ -18,6 +18,7 @@
*/
const hy = {
name: "Հայերեն",
english_name: "Armenian",
code: "hy",
dictionary: {
access_granted_to: "Մուտքը տրված է՝",

View File

@ -18,6 +18,7 @@
*/
const it = {
name: "Italiano",
english_name: "Italian",
code: "it",
dictionary: {
access_granted_to: "Accesso garantito a",

View File

@ -18,6 +18,7 @@
*/
const ko = {
name: "한국어",
english_name: "Korean",
code: "ko",
dictionary: {
access_granted_to: "접근 권한 부여",

View File

@ -18,6 +18,7 @@
*/
const nb = {
name: "Norsk Bokmål",
english_name: "Norwegian Bokmål",
code: "nb",
dictionary: {
access_granted_to: "Tilgang gitt til",

View File

@ -18,6 +18,7 @@
*/
const nn = {
name: "Norsk Nynorsk",
english_name: "Norwegian Nynorsk",
code: "nn",
dictionary: {
access_granted_to: "Tilgang gjeven til",

View File

@ -18,6 +18,7 @@
*/
const ro = {
name: "Română",
english_name: "Romanian",
code: "ro",
dictionary: {
access_granted_to: "Acces acordat pentru",

View File

@ -18,6 +18,7 @@
*/
const sv = {
name: "Svenska",
english_name: "Swedish",
code: "sv",
dictionary: {
access_granted_to: "Tillgång beviljad till",

View File

@ -18,6 +18,7 @@
*/
const th = {
name: "ไทย",
english_name: "Thai",
code: "th",
dictionary: {
access_granted_to: "อนุญาตให้เข้าถึง",

View File

@ -18,6 +18,7 @@
*/
const ur = {
name: "اردو",
english_name: "Urdu",
code: "ur",
dictionary: {
access_granted_to: "رسائی مسموح ہے",

View File

@ -18,6 +18,7 @@
*/
const zh = {
name: "中文",
english_name: "Chinese",
code: "zh",
dictionary: {
access_granted_to: "访问授权给",

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="59px" height="59px" stroke-width="1.7" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M21 7.35304L21 16.647C21 16.8649 20.8819 17.0656 20.6914 17.1715L12.2914 21.8381C12.1102 21.9388 11.8898 21.9388 11.7086 21.8381L3.30861 17.1715C3.11814 17.0656 3 16.8649 3 16.647L2.99998 7.35304C2.99998 7.13514 3.11812 6.93437 3.3086 6.82855L11.7086 2.16188C11.8898 2.06121 12.1102 2.06121 12.2914 2.16188L20.6914 6.82855C20.8818 6.93437 21 7.13514 21 7.35304Z" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path><path d="M3.52844 7.29357L11.7086 11.8381C11.8898 11.9388 12.1102 11.9388 12.2914 11.8381L20.5 7.27777" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 21L12 12" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path></svg>

After

Width:  |  Height:  |  Size: 947 B

1
src/icons/language.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="59px" height="59px" stroke-width="1.4" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12Z" stroke="#000000" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M13 2.04932C13 2.04932 16 5.99994 16 11.9999C16 17.9999 13 21.9506 13 21.9506" stroke="#000000" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M11 21.9506C11 21.9506 8 17.9999 8 11.9999C8 5.99994 11 2.04932 11 2.04932" stroke="#000000" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M2.62964 15.5H21.3704" stroke="#000000" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M2.62964 8.5H21.3704" stroke="#000000" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"></path></svg>

After

Width:  |  Height:  |  Size: 987 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<svg x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
<g stroke-width="3" transform="matrix(0, 1, -1, 0, 47.999504, 0.000014)">
<polyline points="39 24 25 24 25 28" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="3" stroke-linejoin="miter"/>
<polyline points="35.879 10.121 32 14 25 14 25 18" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="3" stroke-linejoin="miter"/>
<path d="M13,26a10.29,10.29,0,0,1-7.2-3" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="3" stroke-linejoin="miter"/>
<path d="M17,31.6A5.826,5.826,0,0,1,13,26a5.731,5.731,0,0,1,2-4.4" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="3" stroke-linejoin="miter"/>
<path d="M35.879,37.879,32,34H25v2A9.9,9.9,0,0,1,15,46,9.9,9.9,0,0,1,5,36a9.058,9.058,0,0,1,.6-3.2A5.627,5.627,0,0,1,3,28a5.888,5.888,0,0,1,2.8-5A9.994,9.994,0,0,1,3,16,9.9,9.9,0,0,1,13,6h.4A5.826,5.826,0,0,1,19,2a5.893,5.893,0,0,1,6,6" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="3" stroke-linejoin="miter"/>
<circle cx="38" cy="8" r="3" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="3" data-color="color-2" stroke-linejoin="miter"/>
<circle cx="42" cy="24" r="3" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="3" data-color="color-2" stroke-linejoin="miter"/>
<circle cx="38" cy="40" r="3" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="3" data-color="color-2" stroke-linejoin="miter"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-palette-fill" viewBox="0 0 16 16">
<path d="M12.433 10.07C14.133 10.585 16 11.15 16 8a8 8 0 1 0-8 8c1.996 0 1.826-1.504 1.649-3.08-.124-1.101-.252-2.237.351-2.92.465-.527 1.42-.237 2.433.07M8 5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3m4.5 3a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3M5 6.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m.5 6.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3"/>
</svg>

After

Width:  |  Height:  |  Size: 464 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="59px" height="59px" stroke-width="1.7" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M20.5096 9.54C20.4243 9.77932 20.2918 9.99909 20.12 10.1863C19.9483 10.3735 19.7407 10.5244 19.5096 10.63C18.2796 11.1806 17.2346 12.0745 16.5002 13.2045C15.7659 14.3345 15.3733 15.6524 15.3696 17C15.3711 17.4701 15.418 17.9389 15.5096 18.4C15.5707 18.6818 15.5747 18.973 15.5215 19.2564C15.4682 19.5397 15.3588 19.8096 15.1996 20.05C15.0649 20.2604 14.8877 20.4403 14.6793 20.5781C14.4709 20.7158 14.2359 20.8085 13.9896 20.85C13.4554 20.9504 12.9131 21.0006 12.3696 21C11.1638 21.0006 9.97011 20.7588 8.85952 20.2891C7.74893 19.8194 6.74405 19.1314 5.90455 18.2657C5.06506 17.4001 4.40807 16.3747 3.97261 15.2502C3.53714 14.1257 3.33208 12.9252 3.36959 11.72C3.4472 9.47279 4.3586 7.33495 5.92622 5.72296C7.49385 4.11097 9.60542 3.14028 11.8496 3H12.3596C14.0353 3.00042 15.6777 3.46869 17.1017 4.35207C18.5257 5.23544 19.6748 6.49885 20.4196 8C20.6488 8.47498 20.6812 9.02129 20.5096 9.52V9.54Z" stroke="#000000" stroke-width="1.7"></path><path d="M8 16.01L8.01 15.9989" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path><path d="M6 12.01L6.01 11.9989" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8 8.01L8.01 7.99889" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 6.01L12.01 5.99889" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path><path d="M16 8.01L16.01 7.99889" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-speedometer2" viewBox="0 0 16 16">
<path d="M8 4a.5.5 0 0 1 .5.5V6a.5.5 0 0 1-1 0V4.5A.5.5 0 0 1 8 4M3.732 5.732a.5.5 0 0 1 .707 0l.915.914a.5.5 0 1 1-.708.708l-.914-.915a.5.5 0 0 1 0-.707M2 10a.5.5 0 0 1 .5-.5h1.586a.5.5 0 0 1 0 1H2.5A.5.5 0 0 1 2 10m9.5 0a.5.5 0 0 1 .5-.5h1.5a.5.5 0 0 1 0 1H12a.5.5 0 0 1-.5-.5m.754-4.246a.39.39 0 0 0-.527-.02L7.547 9.31a.91.91 0 1 0 1.302 1.258l3.434-4.297a.39.39 0 0 0-.029-.518z"/>
<path fill-rule="evenodd" d="M0 10a8 8 0 1 1 15.547 2.661c-.442 1.253-1.845 1.602-2.932 1.25C11.309 13.488 9.475 13 8 13c-1.474 0-3.31.488-4.615.911-1.087.352-2.49.003-2.932-1.25A8 8 0 0 1 0 10m8-7a7 7 0 0 0-6.603 9.329c.203.575.923.876 1.68.63C4.397 12.533 6.358 12 8 12s3.604.532 4.923.96c.757.245 1.477-.056 1.68-.631A7 7 0 0 0 8 3"/>
</svg>

After

Width:  |  Height:  |  Size: 866 B

1
src/icons/user.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="59px" height="59px" stroke-width="1.7" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M5 20V19C5 15.134 8.13401 12 12 12V12C15.866 12 19 15.134 19 19V20" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 12C14.2091 12 16 10.2091 16 8C16 5.79086 14.2091 4 12 4C9.79086 4 8 5.79086 8 8C8 10.2091 9.79086 12 12 12Z" stroke="#000000" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"></path></svg>

After

Width:  |  Height:  |  Size: 557 B

BIN
src/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB