Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#355 fix Avatar uploader jank #375

Merged
merged 22 commits into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1020d00
👽 (user-selectors): update avatar url selector to reflect API updates
UncleClapton Sep 11, 2021
ff627a8
♻️ (user-selectors): rewrite user avatar URL selector for clarity
UncleClapton Sep 11, 2021
a3bf8cc
🔥 remove unused fa icons from library
UncleClapton Sep 12, 2021
7e06391
✨ add faSearch icon to fa lib
UncleClapton Sep 12, 2021
487fb2c
✨♻️🐛 (ProfileUserAvatar): clean up edit button and make it conditiona…
UncleClapton Sep 12, 2021
64ad807
✨ (Slider): add slider component thats an extension of rc-slider
UncleClapton Sep 12, 2021
c56b60c
💄 Add styling for rc-slider
UncleClapton Sep 12, 2021
220a4eb
✨ add file upload icon to lib
UncleClapton Sep 13, 2021
64614b7
🐛 Fix CSP issues for safari
UncleClapton Sep 13, 2021
c826e08
🐛 (switch-scss): ensure icon color is consistent
UncleClapton Sep 13, 2021
8479dd0
💄 continue working on library styling
UncleClapton Sep 13, 2021
7b56836
💄 Add styles for file dropzone
UncleClapton Sep 13, 2021
67f0168
♻️💄 half border width on file dropzone
UncleClapton Sep 13, 2021
5f1e358
🐛💄 (UserDecalPanel): correct font reference
UncleClapton Sep 13, 2021
e09df8e
✨ (MessageBox): expose message box for styling via composes
UncleClapton Sep 13, 2021
3df24c8
✨♻️💄 (UploadAvatarModal): rework component for an improved user exper…
UncleClapton Sep 13, 2021
73e7b69
💄🐛 ensure file dropzones have the correct cursor
UncleClapton Sep 13, 2021
464a5ff
📝 (CHANGELOG.md): add changes introduced by #375
UncleClapton Sep 13, 2021
c60e96d
🐛♻️ prevent selectAvatarUrlByUserId from reporting null selector
UncleClapton Sep 13, 2021
41dcd7b
💄 actually fix cursor, set custom small font size
UncleClapton Sep 13, 2021
895a415
✨ (ProfileUserAvatar): allow size to be controlled by prop
UncleClapton Sep 13, 2021
1e035d1
✨ (UploadAvatarModal) Improve messaging for image upload dropzone and…
UncleClapton Sep 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .config/headers.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ module.exports = (env) => {
'style-src': ["'self'", "'unsafe-inline'", 'fonts.googleapis.com'],
'img-src': ["'self'", '*.wp.com', 'blob:', 'data:'],
'frame-src': ['https://js.stripe.com'],
'child-src': false,
'prefetch-src': false,
'worker-src': false,
},
xssProtection: '1; mode=block;',
}),
},
]
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ For detailed rules of this file, see [Changelog Rules](#changelog-rules)
### ✨ Added
* A new page to assist with editing QMS locale files has been added. - [#370][]
* A general purpose JSON object editor has been implemented. this should come in handy at some point! - [#370][]
* User avatars are now customizable through our new Avatar uploader! - [#332][], [#375][]

### ⚡ Changed
* Error readout for unknown API Errors has been improved. - [#328][]
Expand Down Expand Up @@ -40,9 +41,11 @@ For detailed rules of this file, see [Changelog Rules](#changelog-rules)
[#328]: https://github.com/FuelRats/fuelrats.com/pull/328
[#329]: https://github.com/FuelRats/fuelrats.com/pull/329
[#330]: https://github.com/FuelRats/fuelrats.com/pull/330
[#332]: https://github.com/FuelRats/fuelrats.com/pull/332
[#333]: https://github.com/FuelRats/fuelrats.com/pull/333
[#370]: https://github.com/FuelRats/fuelrats.com/pull/370
[#373]: https://github.com/FuelRats/fuelrats.com/pull/373
[#375]: https://github.com/FuelRats/fuelrats.com/pull/375
[Unreleased]: https://github.com/FuelRats/fuelrats.com/compare/v2.13.0...HEAD


Expand Down
2 changes: 1 addition & 1 deletion src/components/MessageBox/MessageBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function MessageBox (props) {
}

return (
<div className={[styles.message, styles[type], 'message', className]}>
<div className={[styles.message, styles[type], className]}>
<FontAwesomeIcon
className={styles.icon}
icon={icon}
Expand Down
48 changes: 29 additions & 19 deletions src/components/MessageBox/MessageBox.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

.message {
--message-color: #{$red};
composes: message from global;

position: relative;

Expand All @@ -12,26 +13,35 @@
border: 1px solid var(--message-color);

background: rgba($red, 0.15);
}

.error {
--message-color: #{$red};
composes: error from global;

background: rgba($red, 0.15);
}

.success {
--message-color: #{$green};
composes: success from global;

background: rgba($green, 0.15);
}

.info {
--message-color: #{$blue};
composes: info from global;

background: rgba($blue, 0.15);
}

.warn {
--message-color: #{$yellow};

composes: warn from global;

&.error {
--message-color: #{$red};
background: rgba($red, 0.15);
}

&.success {
--message-color: #{$green};
background: rgba($green, 0.15);
}

&.info {
--message-color: #{$blue};
background: rgba($blue, 0.15);
}

&.warn {
--message-color: #{$yellow};
background: rgba($yellow, 0.15);
}
background: rgba($yellow, 0.15);
}

.icon {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ProfileHeader/ProfileHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function ProfileHeader () {
<UnverifiedUserBanner />
)
}
<ProfileUserAvatar />
<ProfileUserAvatar canEdit />
<div className="profile-basic-info">
<div className="rat-name">
{displayRat?.attributes?.name ?? email.split('@')[0]}
Expand Down
69 changes: 54 additions & 15 deletions src/components/ProfileUserAvatar/ProfileUserAvatar.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import Image from 'next/image'
import { useState, useCallback } from 'react'
import PropTypes from 'prop-types'
import { useState, useCallback, useMemo } from 'react'

import useSelectorWithProps from '~/hooks/useSelectorWithProps'
import { selectAvatarByUserId, withCurrentUserId } from '~/store/selectors'
import { selectAvatarUrlByUserId, withCurrentUserId } from '~/store/selectors'

import UploadAvatarModal from '../UploadAvatarModal'
import styles from './ProfileUserAvatar.module.scss'

function ProfileUserAvatar () {
const userAvatar = useSelectorWithProps({ size: 170 }, withCurrentUserId(selectAvatarByUserId))
const faIconLgSize = 100
const faIconMdSize = 64

function ProfileUserAvatar ({
canEdit,
size = 170,
}) {
const userAvatarUrl = useSelectorWithProps({ size }, withCurrentUserId(selectAvatarUrlByUserId))

const [showUploadAvatar, setShowUploadAvatar] = useState(false)

Expand All @@ -19,29 +26,61 @@ function ProfileUserAvatar () {
})
}, [])

const handleAvatarModalClose = useCallback(() => {
return setShowUploadAvatar(false)
}, [])

const sizeMeta = useMemo(() => {
let icon = undefined

if (size >= faIconLgSize) {
icon = '3x'
} else if (size >= faIconMdSize) {
icon = '2x'
}

return {
style: {
width: `${size}px`,
height: `${size}px`,
},
icon,
}
}, [size])

return (
<>
<div className={styles.userAvatar}>
<div className="avatar xl">
<div className="avatar" style={sizeMeta.style}>
<Image
unoptimized
alt="User's avatar"
height={170}
src={userAvatar}
width={170} />
</div>
<div className={styles.userAvatarEdit}>
<div className={[styles.userAvatarEdit, styles.editBack]} />
<button className={[styles.userAvatarEdit, styles.editFace]} type="button" onClick={handleToggleUploadAvatar}>
<FontAwesomeIcon icon="upload" size="3x" />
</button>
height={size}
src={userAvatarUrl}
width={size} />
{
canEdit && (
<button
aria-label="Edit your avatar"
className={[styles.userAvatarEdit, styles.editFace]}
type="button"
onClick={handleToggleUploadAvatar}>
<FontAwesomeIcon icon="upload" size={sizeMeta.icon} />
</button>
)
}
</div>
</div>
<UploadAvatarModal
isOpen={showUploadAvatar}
onClose={handleToggleUploadAvatar} />
onClose={handleAvatarModalClose} />
</>
)
}

ProfileUserAvatar.propTypes = {
canEdit: PropTypes.bool,
size: PropTypes.number,
}

export default ProfileUserAvatar
44 changes: 17 additions & 27 deletions src/components/ProfileUserAvatar/ProfileUserAvatar.module.scss
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
@import '../../scss/colors';

.userAvatar {
position: relative;

grid-area: avatar;

:global(.avatar) {
position: relative;
}
}

.userAvatarEdit {
--background-color: #{rgba($black, 0.7)};
--background-color-hover: var(--background-color);
backdrop-filter: blur(5px);

position: absolute;
top: 0;
left: 0;
z-index: 1;

width: 170px;
height: 170px;
width: 100%;
height: 100%;
margin: 0;
padding: 0;

border: 0.2rem solid $red;
border-radius: 50%;

opacity: 0;
transition: opacity 0.2s;
Expand All @@ -24,28 +36,6 @@
}
}

.editBack {
border: 0.2rem solid $red;
border-radius: 50%;

background: $white;
opacity: 0.8;
}

.editFace {
margin: 0;
padding: 0;

border: none;

color: $black;
background: none;
}

.editFace svg {
position: absolute;
right: 0;
bottom: 0;

color: $black;
color: $red;
}
74 changes: 74 additions & 0 deletions src/components/Slider/Slider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/***
* The renderSliderHandle function within the following component is based on the default handle prop value in .
* https://github.com/react-component/slider/blob/master/src/common/createSlider.tsx#L32
*
* It is licensed under the MIT License below.
*
* The MIT License (MIT)
* Copyright (c) 2015-present Alipay.com, https://www.alipay.com/
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/



import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import RCSlider, { Handle } from 'rc-slider'
import { useCallback } from 'react'





export default function Slider (props) {
const {
Component = RCSlider,
handleIcon: iconId,
iconProps = {},
...restProps
} = props

const renderSliderHandle = useCallback((sliderProps) => {
const { index, ...restSliderProps } = sliderProps
delete restSliderProps.dragging
if (restSliderProps.value === null) {
return null
}

return (
<Handle key={index} {...restSliderProps}>
{
iconId && (
<FontAwesomeIcon
fixedWidth
className="rc-slider-handle-icon"
{...iconProps}
icon={iconId} />
)
}
</Handle>
)
}, [iconProps, iconId])

return (
<Component
handle={renderSliderHandle}
{...restProps} />
)
}
1 change: 1 addition & 0 deletions src/components/Slider/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Slider'
2 changes: 2 additions & 0 deletions src/components/Switch/Switch.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@

border-radius: 50%;

color: $black;

will-change: transform;

background: $red;
Expand Down
12 changes: 8 additions & 4 deletions src/components/UploadAvatarModal/UploadAvatarMessageBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,27 @@ function getErrorText (error) {
}

function UploadAvatarMessageBox (props) {
const { result } = props
const { result, className } = props

return result.success
? (
<MessageBox type="success">
{'Avatar Updated!'}
<MessageBox className={className} title="Success!" type="success">
{'You avatar has been updated!'}
<br />
{'This window will now automatically close...'}
</MessageBox>
)
: (
<ApiErrorBox
className={className}
error={result.error}
renderError={getErrorText} />
)
}

UploadAvatarMessageBox.propTypes = {
result: PropTypes.object,
className: PropTypes.string,
result: PropTypes.object.isRequired,
}

export default UploadAvatarMessageBox
Loading