From b0fb25d590fc2338b0e86350e4536f99ff18deee Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 20 Jun 2025 14:19:34 +0200 Subject: [PATCH] Move profile edition to the settings page --- customize.dist/messages.js | 4 + www/common/cryptpad-common.js | 4 +- www/profile/app-profile.less | 23 --- www/profile/inner.js | 62 +------- www/profile/main.js | 52 +------ www/settings/app-settings.less | 78 ++++++++++ www/settings/inner.js | 255 ++++++++++++++++++++++++++++++++- www/settings/main.js | 17 +++ 8 files changed, 365 insertions(+), 130 deletions(-) diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 9818e3d88..0379bd04d 100755 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -145,6 +145,10 @@ define(req, function(AppConfig, Default, Language) { Messages.hide_password = "Hide password"; Messages.next_templateList = "Next template list"; Messages.previous_templateList = "Previous template list"; + + Messages.settings_profileLinkLabel = "Edit your profile link"; + Messages.settings_profileDescLabel = "Edit your profile description"; + Messages.settings_profileAvatarLabel = "Profile picture"; return Messages; }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 32d887e74..28418598d 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -499,8 +499,8 @@ define([ common.drive.onRemove = Util.mkEvent(); common.drive.onDeleted = Util.mkEvent(); // Profile - common.getProfileEditUrl = function (cb) { - postMessage("GET", { key: ['profile', 'edit'] }, function (obj) { + common.getProfileViewUrl = function (cb) { + postMessage("GET", { key: ['profile', 'view'] }, function (obj) { cb(obj); }); }; diff --git a/www/profile/app-profile.less b/www/profile/app-profile.less index 848a74f48..5dd9ca820 100644 --- a/www/profile/app-profile.less +++ b/www/profile/app-profile.less @@ -28,29 +28,6 @@ margin-top: 1rem; } - .cp-profile-badges { - display: flex; - align-items: center; - & > span { - margin-right: 1em; - } - .cp-profile-badges-list { - .badges_main(40px); - i { - cursor: pointer; - &:focus-visible { - outline: @variables_focus_style; - } - &:not(:last-child) { - margin-right: 0.5em; - } - &.cp-selected { - border-color: @cryptpad_color_brand; - } - } - } - } - #cp-app-profile-header { display: flex; flex-flow: row wrap; diff --git a/www/profile/inner.js b/www/profile/inner.js index 5d4b65849..a1d9bc4e6 100644 --- a/www/profile/inner.js +++ b/www/profile/inner.js @@ -94,7 +94,6 @@ define([ var LINK_ID = "cp-app-profile-link"; var AVATAR_ID = "cp-app-profile-avatar"; var DESCRIPTION_ID = "cp-app-profile-description"; - var BADGES_ID = "cp-app-profile-badges"; var CREATE_ID = "cp-app-profile-create"; var HEADER_ID = "cp-app-profile-header"; var HEADER_RIGHT_ID = "cp-app-profile-rightside"; @@ -381,6 +380,9 @@ define([ $span.empty(); const badge = data?.badge; if (badge && !badgeOK) { + if (!data.proof || !data.edPublic) { + return displayAvatar(val); + } var metadataMgr = common.getMetadataMgr(); var privateData = metadataMgr.getPrivateData(); APP.badge.execCommand('CHECK_BADGE', { @@ -445,10 +447,9 @@ define([ APP.module.execCommand("SET", { key: 'avatar', value: data.url - }, function (err, newData) { + }, function (newData) { sframeChan.query("Q_PROFILE_AVATAR_ADD", data.url, function (err, err2) { if (err || err2) { return void UI.log(err || err2); } - // XXX badge displayAvatar(data.url, newData); }); }); @@ -474,48 +475,6 @@ define([ displayAvatar(data.avatar, data); }; - const addBadges = $container => { - var $block = $('
', {id: BADGES_ID, class:'cp-sidebarlayout-element'}).appendTo($container); - APP.$badges = $(h('span')).appendTo($block); - }; - const refreshBadges = (obj) => { - if (!APP.$badges) { return; } - const metadataMgr = APP.common.getMetadataMgr(); - const privateData = metadataMgr.getPrivateData(); - let args = {}; - if (APP.readOnly) { return; } - if (!privateData.isOwnProfile) { args.edPublic = obj.edPublic; } - APP.badge.execCommand('LIST_BADGES', args, data => { - APP.$badges.empty(); - let spinner; - APP.$badges.toggle(!!data.length); - let all = data.map(str => { - const i = Badges.render(str); - const $i = $(i).attr('tabindex', 0); - if (APP.readOnly) { return i; } - const selected = obj?.badge === str; - if (selected) { $i.addClass('cp-selected'); } - Util.onClickEnter($i, () => { - let value = selected ? '' : str; - spinner.spin(); - APP.module.execCommand('SET', { - key: 'badge', - value - }, function (data) { - spinner.hide(); - APP.updateValues(data); - }); - }); - return i; - }); - let content = h('div.cp-profile-badges', [ - h('span', Messages.profile_badges), - h('div.cp-profile-badges-list', all) - ]); - APP.$badges.append(content); - spinner = UI.makeSpinner(APP.$badges.find('> div')); - }); - }; var addDescription = function ($container) { var $block = $('
', {id: DESCRIPTION_ID, class: PROFILE_SECTION}).appendTo($container); @@ -679,7 +638,6 @@ define([ addLink($rightside); addFriendRequest($rightside); addMuteButton($rightside); - addBadges($rightside); addPublicKey($rightside); addCopyData($rightside); addViewButton($rightside); @@ -689,18 +647,14 @@ define([ } }; - var updateValues = APP.updateValues = function (data) { + var updateValues = APP.updateValues = function (_data) { + const data = Util.clone(_data); // Only update avatar if it has changed - if (!APP._lastUpdate - || APP._lastUpdate.avatar !== data.avatar - || APP._lastUpdate.badge !== data.badge) { - refreshAvatar(data); - } + refreshAvatar(data); // Always update other profile information refreshName(data); refreshLink(data); refreshDescription(data); - refreshBadges(data); refreshFriendRequest(data); refreshMute(data); setPublicKeyButton(data); @@ -778,7 +732,6 @@ define([ onEvent: onEvent }); if (privateData.isOwnProfile) { - APP.module = common.makeUniversal('profile', { onEvent: onEvent }); @@ -786,7 +739,6 @@ define([ init(); - console.log('POST SUBSCRIBE'); execCommand('SUBSCRIBE', null, function (obj) { updateValues(obj); UI.removeLoadingScreen(); diff --git a/www/profile/main.js b/www/profile/main.js index ca36121c5..76ebde55d 100644 --- a/www/profile/main.js +++ b/www/profile/main.js @@ -18,40 +18,15 @@ define([ }).nThen(function (/*waitFor*/) { var getSecrets = function (Cryptpad, Utils, cb) { var Hash = Utils.Hash; - // 1st case: visiting someone else's profile with hash in the URL + // hash in the URL: visit someone else's profile if (window.location.hash) { // No password for profiles - return void cb(null, Hash.getSecrets('profile', window.location.hash.slice(1))); + const hash = window.location.hash.slice(1); + return cb(null, Hash.getSecrets('profile', hash)); } - nThen(function (waitFor) { - // 2nd case: visiting our own existing profile - Cryptpad.getProfileEditUrl(waitFor(function (hash) { - waitFor.abort(); - return void cb(null, Hash.getSecrets('profile', hash)); - })); - }).nThen(function () { - if (!Utils.LocalStore.isLoggedIn()) { - // Unregistered users can't create a profile - window.location.href = '/drive/'; - return void cb(); - } - // No password for profile - var hash = Hash.createRandomHash('profile'); - var secret = Hash.getSecrets('profile', hash); - Cryptpad.pinPads([secret.channel], function (e) { - if (e) { - if (e === 'E_OVER_LIMIT') { - // TODO - } - return; - //return void UI.log(Messages._getKey('profile_error', [e])) // TODO - } - var profile = {}; - profile.edit = Utils.Hash.getEditHashFromKeys(secret); - profile.view = Utils.Hash.getViewHashFromKeys(secret); - Cryptpad.setNewProfile(profile); - }); - cb(null, secret); + // open our own profile + Cryptpad.getProfileViewUrl(function (hash) { + cb(null, Hash.getSecrets('profile', hash)); }); }; var addData = function (meta, Cryptpad, user) { @@ -59,21 +34,6 @@ define([ window.location.hash.slice(1) === user.profile; }; var addRpc = function (sframeChan, Cryptpad, Utils) { - // Adding a new avatar from the profile: pin it and store it in the object - sframeChan.on('Q_PROFILE_AVATAR_ADD', function (data, cb) { - var chanId = Utils.Hash.hrefToHexChannelId(data, null); - Cryptpad.pinPads([chanId], function (e) { - if (e) { return void cb(e); } - Cryptpad.setAvatar(data, cb); - }); - }); - // Removing the avatar from the profile: unpin it - sframeChan.on('Q_PROFILE_AVATAR_REMOVE', function (data, cb) { - var chanId = Utils.Hash.hrefToHexChannelId(data, null); - Cryptpad.unpinPads([chanId], function () { - Cryptpad.setAvatar(undefined, cb); - }); - }); sframeChan.on('EV_PROFILE_CORRUPTED_CACHE', function () { Utils.Cache.clearChannel(Utils.secret.channel, function () { diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index 365c53c3d..6832c7a09 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -9,6 +9,8 @@ @import (reference) "../../customize/src/less2/include/creation.less"; @import (reference) '../../customize/src/less2/include/framework.less'; @import (reference) '../../customize/src/less2/include/export.less'; +@import (reference) '../../customize/src/less2/include/badges.less'; +@import (reference) '../../customize/src/less2/include/avatar.less'; &.cp-app-settings { .framework_min_main(); @@ -229,6 +231,82 @@ margin: 0 2px 0 0; } } + .cp-settings-badges { + display: flex; + flex-flow: column; + align-items: flex-start; + .cp-settings-badges-list { + display: flex; + align-items: center; + font-size: 24px; + margin-top: 10px; + .badges_main(40px); + i { + cursor: pointer; + &:focus-visible { + outline: @variables_focus_style; + } + &:not(:last-child) { + margin-right: 0.5em; + } + &.cp-selected { + border-color: @cryptpad_color_brand; + } + } + } + } + .cp-settings-profile-avatar { + .cp-settings-avatar-container { + width: 320px; + background: @cryptpad_text_col; + padding: 10px; + margin-top: 10px; + border-radius: 10px; + } + .cp-avatar { + box-sizing: content-box; + .avatar_main(300px); + display: flex; + text-align: center; + border-radius: 4px; + overflow: visible; + position: relative; + .cp-settings-avatar-delete { + right: 0; + top: 0; + position: absolute; + opacity: 1; + &:hover { + opacity: 0.7; + } + } + } + img { + max-width: 100%; + max-height: 100%; + vertical-align: top; + border-radius: @variables_radius_L; + } + media-tag { + height: 100%; + width: 100%; + display: inline-flex; + justify-content: center; + align-items: center; + img { + min-width: 100%; + min-height: 100%; + max-width: none; + max-height: none; + flex: 1; + } + } + button { + min-width: 40px; + height: 40px; + margin: 5px !important; + } + } } } diff --git a/www/settings/inner.js b/www/settings/inner.js index f65d7a555..dd8a7ee4b 100644 --- a/www/settings/inner.js +++ b/www/settings/inner.js @@ -11,6 +11,9 @@ define([ '/common/common-ui-elements.js', '/common/common-util.js', '/common/common-hash.js', + '/common/inner/sidebar-layout.js', + '/common/inner/badges.js', + '/common/inner/common-mediatag.js', '/customize/messages.js', '/common/hyperscript.js', '/common/common-credential.js', @@ -35,6 +38,9 @@ define([ UIElements, Util, Hash, + Sidebar, + Badges, + MT, Messages, h, Cred, @@ -52,17 +58,23 @@ define([ var metadataMgr; var privateData; var sframeChan; - + var onProfileEvt = Util.mkEvent(); var categories = { 'account': [ // Msg.settings_cat_account 'cp-settings-own-drive', 'cp-settings-info-block', - 'cp-settings-displayname', 'cp-settings-language-selector', 'cp-settings-mediatag-size', 'cp-settings-delete' ], + 'profile': [ // Msg.settings_cat_profile + 'cp-settings-displayname', + 'cp-settings-profile-avatar', + 'cp-settings-profile-badges', + 'cp-settings-profile-link', + 'cp-settings-profile-description', + ], 'security': [ // Msg.settings_cat_security 'cp-settings-logout-everywhere', 'cp-settings-mfa', @@ -146,11 +158,14 @@ define([ .text(Messages['settings_' + safeKey + 'Hint'] || 'Coming soon...'); }; - var makeBlock = function(key, getter, full) { + var makeBlock = function(key, getter, full, isNew) { var safeKey = key.replace(/-([a-z])/g, function(g) { return g[1].toUpperCase(); }); create[key] = function() { var $div = $('
', { 'class': 'cp-settings-' + key + ' cp-sidebarlayout-element' }); + if (isNew) { + $div.attr('data-item', key); + } if (full) { $('