diff --git a/res/css/views/settings/_AvatarSetting.scss b/res/css/views/settings/_AvatarSetting.scss index eddcf9f55a..871b436ba6 100644 --- a/res/css/views/settings/_AvatarSetting.scss +++ b/res/css/views/settings/_AvatarSetting.scss @@ -1,5 +1,5 @@ /* -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,13 +15,55 @@ limitations under the License. */ .mx_AvatarSetting_avatar { - width: $font-88px; - height: $font-88px; - margin-left: 13px; + width: 90px; + height: 90px; + margin-top: 8px; position: relative; + .mx_AvatarSetting_hover { + transition: opacity 0.08s cubic-bezier(.46, .03, .52, .96); // quadratic + + // position to place the hover bg over the entire thing + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + + pointer-events: none; // let the pointer fall through the underlying thing + + line-height: 90px; + text-align: center; + + > span { + color: #fff; // hardcoded to contrast with background + position: relative; // tricks the layout engine into putting this on top of the bg + font-weight: 500; + } + + .mx_AvatarSetting_hoverBg { + // absolute position to lazily fill the entire container + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + + opacity: 0.5; + background-color: $settings-profile-overlay-placeholder-fg-color; + border-radius: 90px; + } + } + + &.mx_AvatarSetting_avatar_hovering .mx_AvatarSetting_hover { + opacity: 1; + } + + &:not(.mx_AvatarSetting_avatar_hovering) .mx_AvatarSetting_hover { + opacity: 0; + } + & > * { - width: $font-88px; box-sizing: border-box; } @@ -30,7 +72,7 @@ limitations under the License. } .mx_AccessibleButton.mx_AccessibleButton_kind_link_sm { - color: $button-danger-bg-color; + width: 100%; } & > img { @@ -41,8 +83,9 @@ limitations under the License. & > img, .mx_AvatarSetting_avatarPlaceholder { display: block; - height: $font-88px; - border-radius: 4px; + height: 90px; + border-radius: 90px; + cursor: pointer; } .mx_AvatarSetting_avatarPlaceholder::before { @@ -58,6 +101,34 @@ limitations under the License. left: 0; right: 0; } + + .mx_AvatarSetting_avatarPlaceholder ~ .mx_AvatarSetting_uploadButton { + border: 1px solid $settings-profile-overlay-placeholder-fg-color; + } + + .mx_AvatarSetting_uploadButton { + width: 32px; + height: 32px; + border-radius: 32px; + background-color: $settings-profile-placeholder-bg-color; + + position: absolute; + bottom: 0; + right: 0; + } + + .mx_AvatarSetting_uploadButton::before { + content: ""; + display: block; + width: 100%; + height: 100%; + mask-repeat: no-repeat; + mask-position: center; + mask-size: 55%; + background-color: $settings-profile-overlay-placeholder-fg-color; + mask-image: url('$(res)/img/feather-customised/edit.svg'); + } + } .mx_AvatarSetting_avatar .mx_AvatarSetting_avatarPlaceholder { diff --git a/res/css/views/settings/_ProfileSettings.scss b/res/css/views/settings/_ProfileSettings.scss index 58624d1597..732cbedf02 100644 --- a/res/css/views/settings/_ProfileSettings.scss +++ b/res/css/views/settings/_ProfileSettings.scss @@ -1,5 +1,5 @@ /* -Copyright 2019 New Vector Ltd +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,13 @@ limitations under the License. .mx_ProfileSettings_controls { flex-grow: 1; + margin-right: 54px; + + // We put the header under the controls with some minor styling to cheat + // alignment of the field with the avatar + .mx_SettingsTab_subheading { + margin-top: 0; + } } .mx_ProfileSettings_controls .mx_Field #profileTopic { @@ -41,3 +48,17 @@ limitations under the License. .mx_ProfileSettings_avatarUpload { display: none; } + +.mx_ProfileSettings_profileForm { + @mixin mx_Settings_fullWidthField; + border-bottom: 1px solid $menu-border-color; +} + +.mx_ProfileSettings_buttons { + margin-top: 10px; // 18px is already accounted for by the
above the buttons + margin-bottom: 28px; + + > .mx_AccessibleButton_kind_link { + padding-left: 0; // to align with left side + } +} diff --git a/src/components/views/room_settings/RoomProfileSettings.js b/src/components/views/room_settings/RoomProfileSettings.js index f657fbf509..621c8b287e 100644 --- a/src/components/views/room_settings/RoomProfileSettings.js +++ b/src/components/views/room_settings/RoomProfileSettings.js @@ -75,6 +75,15 @@ export default class RoomProfileSettings extends React.Component { }); }; + _clearProfile = async (e) => { + e.stopPropagation(); + e.preventDefault(); + + if (!this.state.enableProfileSave) return; + this._removeAvatar(); + this.setState({enableProfileSave: false, displayName: this.state.originalDisplayName}); + }; + _saveProfile = async (e) => { e.stopPropagation(); e.preventDefault(); @@ -150,7 +159,11 @@ export default class RoomProfileSettings extends React.Component { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const AvatarSetting = sdk.getComponent('settings.AvatarSetting'); return ( -
); } diff --git a/src/components/views/settings/AvatarSetting.js b/src/components/views/settings/AvatarSetting.js index 888d99ca49..580ebdcdad 100644 --- a/src/components/views/settings/AvatarSetting.js +++ b/src/components/views/settings/AvatarSetting.js @@ -14,25 +14,25 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useCallback} from "react"; +import React, {useState} from "react"; import PropTypes from "prop-types"; - -import * as sdk from "../../../index"; import {_t} from "../../../languageHandler"; -import Modal from "../../../Modal"; +import AccessibleButton from "../elements/AccessibleButton"; +import classNames from "classnames"; const AvatarSetting = ({avatarUrl, avatarAltText, avatarName, uploadAvatar, removeAvatar}) => { - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + const [isHovering, setIsHovering] = useState(); + const hoveringProps = { + onMouseEnter: () => setIsHovering(true), + onMouseLeave: () => setIsHovering(false), + }; - const openImageView = useCallback(() => { - const ImageView = sdk.getComponent("elements.ImageView"); - Modal.createDialog(ImageView, { - src: avatarUrl, - name: avatarName, - }, "mx_Dialog_lightbox"); - }, [avatarUrl, avatarName]); - - let avatarElement = ; + let avatarElement =