mirror of
https://github.com/filecoin-project/slate.git
synced 2024-11-09 20:28:29 +03:00
Merge pull request #846 from filecoin-project/@aminejv/responsive-profile-photo
Fix: responsive profile photo
This commit is contained in:
commit
8d1eeb272f
@ -390,3 +390,17 @@ export const useFollowProfileHandler = ({ user, viewer, onAction }) => {
|
||||
|
||||
return { handleFollow, isFollowing };
|
||||
};
|
||||
|
||||
// NOTE(amine): use this hook when we need to evaluate dependencies manually
|
||||
export function useMemoCompare(next, compare) {
|
||||
const previousRef = React.useRef();
|
||||
const previous = previousRef.current;
|
||||
|
||||
const isEqual = compare(previous, next);
|
||||
|
||||
if (!isEqual) {
|
||||
previousRef.current = next;
|
||||
}
|
||||
|
||||
return isEqual ? previous : next;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import BCrypt from "bcryptjs";
|
||||
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Validations from "~/common/validations";
|
||||
import * as Constants from "~/common/constants";
|
||||
|
||||
//NOTE(martina): this file is for utility functions that do not involve API calls
|
||||
//For API related utility functions, see common/user-behaviors.js
|
||||
@ -133,3 +134,33 @@ export const getTimeDifferenceFromNow = (date, format = {}) => {
|
||||
|
||||
return formatDate.default(month, day, year);
|
||||
};
|
||||
|
||||
const isObject = (val) => val instanceof Object;
|
||||
|
||||
/**
|
||||
NOTE(amine): This will take a prop and return a responsive object that we can use with emotion.
|
||||
Let's say we have a size prop with current values {base: 64, mobile: 120}, and a mapper function
|
||||
(size)=> ({width: size, height: size}).
|
||||
It will return a responsive object
|
||||
{ width: 64, height: 64,
|
||||
'@media (min-width: 768px':{ width: 120, height: 120 } }
|
||||
*/
|
||||
export function mapResponsiveProp(prop, mapper) {
|
||||
if (isObject(prop)) {
|
||||
const { base, ...restProps } = prop;
|
||||
let initialStyles = mapper(base) || {};
|
||||
|
||||
return Object.keys(restProps).reduce((styles, size) => {
|
||||
const media = `@media (min-width: ${Constants.sizes[size]}px)`;
|
||||
const mediaStyles = mapper(restProps[size]);
|
||||
styles[media] = mediaStyles;
|
||||
return styles;
|
||||
}, initialStyles);
|
||||
}
|
||||
|
||||
if (prop !== null) {
|
||||
return mapper(prop);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -612,7 +612,7 @@ export default class Profile extends React.Component {
|
||||
<div css={STYLES_PROFILE_BACKGROUND}>
|
||||
<div css={STYLES_PROFILE_INFO}>
|
||||
<div css={STYLES_PROFILE_IMAGE}>
|
||||
<ProfilePhoto user={user} size={120} />
|
||||
<ProfilePhoto user={user} size={{ base: 64, mobile: 120 }} />
|
||||
{showStatusIndicator && this.checkStatus({ id: user.id }) && (
|
||||
<div css={STYLES_STATUS_INDICATOR} />
|
||||
)}
|
||||
|
@ -1,7 +1,10 @@
|
||||
import * as React from "react";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as Utilities from "~/common/utilities";
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { useMemoCompare } from "~/common/hooks";
|
||||
import isEqual from "lodash/isEqual";
|
||||
|
||||
import Dismissible from "~/components/core/Dismissible";
|
||||
|
||||
@ -26,56 +29,59 @@ const STYLES_AVATAR_ONLINE = css`
|
||||
border-radius: 16px;
|
||||
`;
|
||||
|
||||
function BoringAvatar(props) {
|
||||
let colors = ['A9B9C1', '5B6B74', '3C444A', 'D4DBDF', '293137'];
|
||||
function BoringAvatar({ avatarCss, ...props }) {
|
||||
let colors = ["A9B9C1", "5B6B74", "3C444A", "D4DBDF", "293137"];
|
||||
let avatarUrl = `https://source.boringavatars.com/marble/${props.size}/${props.userId}?square&colors=${colors}`;
|
||||
return (
|
||||
<Dismissible
|
||||
captureResize={false}
|
||||
captureScroll={true}
|
||||
>
|
||||
<Dismissible captureResize={false} captureScroll={true}>
|
||||
<img
|
||||
src={avatarUrl}
|
||||
css={STYLES_AVATAR}
|
||||
css={[avatarCss, STYLES_AVATAR]}
|
||||
style={{
|
||||
width: `${props.size}px`,
|
||||
height: `${props.size}px`,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
alt="profile preview"
|
||||
/>
|
||||
</Dismissible>
|
||||
);
|
||||
}
|
||||
|
||||
function UploadedAvatar(props) {
|
||||
function UploadedAvatar({ avatarCss, ...props }) {
|
||||
return (
|
||||
<Dismissible
|
||||
css={STYLES_AVATAR}
|
||||
captureResize={false}
|
||||
captureScroll={true}
|
||||
style={{
|
||||
...props.style,
|
||||
width: `${props.size}px`,
|
||||
height: `${props.size}px`,
|
||||
backgroundImage: `url('${props.url}')`,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
{props.visible ? props.popover : null}
|
||||
{props.online ? <span css={STYLES_AVATAR_ONLINE} /> : null}
|
||||
</Dismissible>
|
||||
)
|
||||
css={[avatarCss, STYLES_AVATAR]}
|
||||
captureResize={false}
|
||||
captureScroll={true}
|
||||
style={{
|
||||
...props.style,
|
||||
backgroundImage: `url('${props.url}')`,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
{props.visible ? props.popover : null}
|
||||
{props.online ? <span css={STYLES_AVATAR_ONLINE} /> : null}
|
||||
</Dismissible>
|
||||
);
|
||||
}
|
||||
|
||||
export default class ProfilePhoto extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
{this.props.user.data.photo
|
||||
? <UploadedAvatar url={this.props.user.data.photo} size={this.props.size} />
|
||||
: <BoringAvatar userId={this.props.user.id} size={this.props.size} />
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default function ProfilePhoto({ size, ...props }) {
|
||||
// NOTE(amine): will calculate only when the size prop changes
|
||||
const memoizedSizeProp = useMemoCompare(size, isEqual);
|
||||
const STYLES_SIZE = React.useMemo(() => {
|
||||
const responsiveStyles = Utilities.mapResponsiveProp(size, (size) => ({
|
||||
width: size,
|
||||
height: size,
|
||||
}));
|
||||
return css(responsiveStyles);
|
||||
}, [memoizedSizeProp]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{props.user.data.photo ? (
|
||||
<UploadedAvatar url={props.user.data.photo} avatarCss={STYLES_SIZE} />
|
||||
) : (
|
||||
<BoringAvatar userId={props.user.id} avatarCss={STYLES_SIZE} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user