diff --git a/package-lock.json b/package-lock.json index 17e1548a..5c69d128 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,9 +46,6 @@ "webpack": "^5.88.2", "webpack-cli": "^5.1.1" }, - "engines": { - "node": ">=20.0.0" - }, "optionalDependencies": { "sharp": "^0.34.3", "sharp-bmp": "^0.1.5", @@ -2316,7 +2313,7 @@ "resolved": "src/puter-wisp", "link": true }, - "node_modules/@heyputer/puter.js": { + "node_modules/@heyputer/puterjs": { "resolved": "src/puter-js", "link": true }, @@ -20241,7 +20238,7 @@ "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-replace": "^5.0.2", "mocha": "^10.8.2", - "rollup": "^3.29.5", + "rollup": "^3.21.4", "rollup-plugin-copy": "^3.4.0" }, "optionalDependencies": { @@ -20376,12 +20373,11 @@ "license": "AGPL-3.0-only" }, "src/puter-js": { - "name": "@heyputer/puter.js", - "version": "2.0.11", + "name": "@heyputer/puterjs", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@heyputer/kv.js": "^0.1.92", - "@heyputer/putility": "^1.0.3" + "@heyputer/kv.js": "^0.1.92" }, "devDependencies": { "concurrently": "^8.2.2", @@ -20395,7 +20391,7 @@ }, "src/putility": { "name": "@heyputer/putility", - "version": "1.0.3", + "version": "1.0.2", "license": "AGPL-3.0-only" }, "src/terminal": { @@ -20412,7 +20408,7 @@ "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-replace": "^5.0.2", "http-server": "^14.1.1", - "mocha": "^10.8.2", + "mocha": "^10.2.0", "rollup": "^3.29.5", "rollup-plugin-copy": "^3.4.0" } diff --git a/src/gui/src/UI/Components/PasswordEntry.js b/src/gui/src/UI/Components/PasswordEntry.js index da5e3ee1..90ecaf93 100644 --- a/src/gui/src/UI/Components/PasswordEntry.js +++ b/src/gui/src/UI/Components/PasswordEntry.js @@ -1,12 +1,23 @@ /** - * Improved PasswordEntry Component for Puter GUI - * Features: - * - DRY: input styles reused from shared CSS class - * - Password strength meter (weak/medium/strong) - * - Caps Lock warning - * - Accessible show/hide toggle button + * 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 . */ + const Component = use('util.Component'); export default def(class PasswordEntry extends Component { @@ -25,73 +36,80 @@ export default def(class PasswordEntry extends Component { display: flex; flex-direction: column; } + input { + flex-grow: 1; + } + /* TODO: I'd rather not duplicate this */ + .error { + display: none; + color: red; + border: 1px solid red; + border-radius: 4px; + padding: 9px; + margin-bottom: 15px; + text-align: center; + font-size: 13px; + } .error-message { display: none; color: rgb(215 2 2); font-size: 14px; - margin: 10px 0; + margin-top: 10px; + margin-bottom: 10px; padding: 10px; border-radius: 4px; border: 1px solid rgb(215 2 2); text-align: center; } - .password-and-toggle { display: flex; align-items: center; gap: 10px; } - .password-and-toggle input { flex-grow: 1; } - .strength-meter { - height: 6px; + + /* TODO: DRY: This is from style.css */ + input[type=text], input[type=password], input[type=email], select { + width: 100%; + padding: 8px; + border: 1px solid #ccc; border-radius: 4px; - margin-top: 6px; - background: #eee; - overflow: hidden; + box-sizing: border-box; + outline: none; + -webkit-font-smoothing: antialiased; + color: #393f46; + font-size: 14px; } - .strength-bar { - height: 100%; - width: 0%; - transition: width 0.3s; + /* to prevent auto-zoom on input focus in mobile */ + .device-phone input[type=text], .device-phone input[type=password], .device-phone input[type=email], .device-phone select { + font-size: 17px; } - .strength-weak { background: #e74c3c; } - .strength-medium { background: #f39c12; } - .strength-strong { background: #2ecc71; } - - .caps-warning { - display: none; - font-size: 12px; - margin-top: 5px; - color: #e67e22; + input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, select:focus { + border: 2px solid #01a0fd; + padding: 7px; } `; create_template ({ template }) { $(template).html(/*html*/`
-
+
- - + +
-
-
-
-
⚠️ Caps Lock is ON
`); } @@ -101,73 +119,38 @@ export default def(class PasswordEntry extends Component { } on_ready ({ listen }) { - const input = $(this.dom_).find('#password'); - const strengthBar = $(this.dom_).find('.strength-bar'); - const capsWarning = $(this.dom_).find('.caps-warning'); - const errorBox = $(this.dom_).find('.error-message'); - - // Show errors listen('error', (error) => { - if (!error) return errorBox.hide(); - errorBox.text(error).show(); + if ( ! error ) return $(this.dom_).find('.error').hide(); + $(this.dom_).find('.error').text(error).show(); }); - // Reset input value if cleared listen('value', (value) => { - if (value === undefined) input.val(''); + // clear input + if ( value === undefined ) { + $(this.dom_).find('input').val(''); + } }); - // Input listener + const input = $(this.dom_).find('input'); input.on('input', () => { - const value = input.val(); - this.set('value', value); - this.updateStrength(value, strengthBar); + this.set('value', input.val()); }); - // Caps Lock detection - input.on('keyup keydown', (e) => { - const isCaps = e.getModifierState && e.getModifierState('CapsLock'); - capsWarning.toggle(isCaps); - }); - - // Submit on Enter const on_submit = this.get('on_submit'); - if (on_submit) { - input.on('keyup', (e) => { - if (e.key === 'Enter') on_submit(); + if ( on_submit ) { + $(this.dom_).find('input').on('keyup', (e) => { + if ( e.key === 'Enter' ) { + on_submit(); + } }); } - - // Toggle password visibility - $(this.dom_).find('#toggle-show-password').on('click', () => { + + $(this.dom_).find("#toggle-show-password").on("click", () => { this.set('show_password', !this.get('show_password')); const show_password = this.get('show_password'); - - input.attr("type", show_password ? "text" : "password"); - - const icon = show_password - ? window.icons["eye-closed.svg"] - : window.icons["eye-open.svg"]; - $(this.dom_).find("#toggle-show-password img").attr("src", icon); + // hide/show password and update icon + $(this.dom_).find("input").attr("type", show_password ? "text" : "password"); + $(this.dom_).find("#toggle-show-password").attr("src", show_password ? window.icons["eye-closed.svg"] : window.icons["eye-open.svg"]) }); } - - updateStrength(value, bar) { - let strength = 0; - if (value.length > 5) strength++; - if (/[A-Z]/.test(value)) strength++; - if (/[0-9]/.test(value)) strength++; - if (/[^A-Za-z0-9]/.test(value)) strength++; - - let width = "0%"; - let cls = ""; - - if (strength === 1) { width = "33%"; cls = "strength-weak"; } - if (strength === 2) { width = "66%"; cls = "strength-medium"; } - if (strength >= 3) { width = "100%"; cls = "strength-strong"; } - - bar.removeClass("strength-weak strength-medium strength-strong") - .addClass(cls) - .css("width", width); - } });