added new profile avatars

Replaced the old avatar component with a new ProfilePhoto component. The component has logic to use a BoringAvatar if the user hasn't uploaded a photo yet.
This commit is contained in:
jasonleyser 2021-07-13 17:39:11 -06:00
parent b10accf732
commit d73be6a91d
8 changed files with 132 additions and 47 deletions

View File

@ -6,6 +6,7 @@ import * as UserBehaviors from "~/common/user-behaviors";
import { PopoverNavigation } from "~/components/system";
import { css } from "@emotion/react";
import { Link } from "~/components/core/Link";
import ProfilePhoto from "~/components/core/ProfilePhoto";
import { Boundary } from "~/components/system/components/fragments/Boundary";
@ -118,16 +119,14 @@ export class ApplicationUserControlsPopup extends React.Component {
if (this.props.popup === "profile") {
const topSection = (
<div css={Styles.HORIZONTAL_CONTAINER} style={{ marginBottom: 14 }}>
<span
css={STYLES_PROFILE_IMAGE}
style={{
cursor: "default",
width: 46,
height: 46,
marginRight: 16,
backgroundImage: `url('${this.props.viewer.data.photo}')`,
}}
/>
<div style={{ marginRight: '16px', cursor: 'default' }} >
<ProfilePhoto
size={46}
userId={this.props.viewer.id}
photo={this.props.viewer.data.photo}
/>
</div>
<div
css={Styles.VERTICAL_CONTAINER}
style={{
@ -273,17 +272,20 @@ export class ApplicationUserControlsPopup extends React.Component {
}
export class ApplicationUserControls extends React.Component {
render() {
let tooltip = <ApplicationUserControlsPopup {...this.props} />;
return (
<div css={STYLES_HEADER}>
<div css={STYLES_PROFILE_MOBILE} style={{ position: "relative" }}>
<span
css={STYLES_PROFILE_IMAGE}
onClick={() => this.props.onTogglePopup("profile")}
style={{
backgroundImage: `url('${this.props.viewer.data.photo}')`,
}}
<div
css={STYLES_PROFILE_MOBILE}
onClick={() => this.props.onTogglePopup("profile")}
style={{ position: "relative", cursor: 'pointer' }}
>
<ProfilePhoto
photo={this.props.viewer.data.photo}
userId={this.props.viewer.id}
size={24}
/>
{this.props.popup === "profile" ? tooltip : null}
</div>

View File

@ -23,6 +23,7 @@ import SlatePreviewBlocks from "~/components/core/SlatePreviewBlock";
import CTATransition from "~/components/core/CTATransition";
import DataView from "~/components/core/DataView";
import EmptyState from "~/components/core/EmptyState";
import ProfilePhoto from "~/components/core/ProfilePhoto";
const STYLES_PROFILE_BACKGROUND = css`
background-color: ${Constants.system.white};
@ -243,14 +244,15 @@ const STYLES_DIRECTORY_NAME = css`
function UserEntry({ user, button, onClick, message, checkStatus }) {
const isOnline = checkStatus({ id: user.id });
return (
<div key={user.username} css={STYLES_USER_ENTRY}>
<div css={STYLES_USER} onClick={onClick}>
<div
css={STYLES_DIRECTORY_PROFILE_IMAGE}
style={{ backgroundImage: `url(${user.data.photo})` }}
>
<div css={STYLES_DIRECTORY_PROFILE_IMAGE}>
<ProfilePhoto
photo={user.data.photo}
userId={user.id}
size={24}
/>
{isOnline && <div css={STYLES_DIRECTORY_STATUS_INDICATOR} />}
</div>
<span css={STYLES_DIRECTORY_NAME}>

View File

@ -0,0 +1,81 @@
import * as React from "react";
import * as Constants from "~/common/constants";
import { css } from "@emotion/react";
import Dismissible from "~/components/core/Dismissible";
const STYLES_AVATAR = css`
display: inline-flex;
background-size: cover;
background-position: 50% 50%;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
position: relative;
border-radius: 4px;
background-color: ${Constants.system.black};
`;
const STYLES_AVATAR_ONLINE = css`
height: 16px;
width: 16px;
background-color: ${Constants.system.green};
border: 2px solid ${Constants.system.white};
position: absolute;
bottom: -4px;
right: -4px;
border-radius: 16px;
`;
function BoringAvatar(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}
>
<img
src={avatarUrl}
css={STYLES_AVATAR}
style={{
width: `${props.size}px`,
height: `${props.size}px`,
cursor: "pointer",
}}
/>
</Dismissible>
);
}
function UploadedAvatar(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>
)
}
export default class ProfilePhoto extends React.Component {
render() {
return (
<>
{this.props.photo
? <UploadedAvatar url={this.props.photo} size={this.props.size} />
: <BoringAvatar userId={this.props.userId} size={this.props.size} />
}
</>
);
}
}

View File

@ -17,6 +17,7 @@ import { Boundary } from "~/components/system/components/fragments/Boundary";
import { PopoverNavigation } from "~/components/system/components/PopoverNavigation";
import { FileTypeIcon } from "~/components/core/FileTypeIcon";
import { useIntercom } from "react-use-intercom";
import ProfilePhoto from "~/components/core/ProfilePhoto";
const STYLES_MOBILE_HIDDEN = css`
@media (max-width: ${Constants.sizes.mobile}px) {
@ -83,7 +84,13 @@ const UserEntry = ({ user }) => {
return (
<div css={STYLES_ENTRY}>
<div css={STYLES_ENTRY_CONTAINER}>
<div style={{ backgroundImage: `url(${user.data.photo})` }} css={STYLES_PROFILE_PREVIEW} />
<div css={STYLES_PROFILE_PREVIEW}>
<ProfilePhoto
photo={user.data.photo}
userId={user.id}
size={48}
/>
</div>
<div css={STYLES_TEXT_ROWS}>
{user.data.name ? (
<React.Fragment>
@ -113,7 +120,14 @@ const STYLES_PROFILE_IMAGE = css`
const UserPreview = ({ user }) => {
return (
<div>
<div css={STYLES_PROFILE_IMAGE} style={{ backgroundImage: `url('${user.data.photo}')` }} />
<div css={STYLES_PROFILE_IMAGE}>
<ProfilePhoto
photo={user.data.photo}
userId={user.id}
size={182}
/>
</div>
{user.data.name ? <div css={STYLES_PREVIEW_TEXT}>{user.data.name}</div> : null}
<div css={STYLES_PREVIEW_TEXT}>@{user.username}</div>
{user.data.slates ? (

View File

@ -103,18 +103,12 @@ export default async (req, res) => {
.send({ decorator: "SERVER_CREATE_USER_BUCKET_INIT_FAILURE", error: true });
}
const photo = await SlateManager.getRandomSlateElementURL({
id: Environment.AVATAR_SLATE_ID,
fallback:
"https://slate.textile.io/ipfs/bafkreick3nscgixwfpq736forz7kzxvvhuej6kszevpsgmcubyhsx2pf7i",
});
const user = await Data.createUser({
username: newUsername,
email: newEmail,
twitterId: twitterUser.id_str,
data: {
photo,
photo: "",
body: "",
settings: {
settings_deals_auto_approve: false,

View File

@ -85,18 +85,12 @@ export default async (req, res) => {
.send({ decorator: "SERVER_CREATE_USER_BUCKET_INIT_FAILURE", error: true });
}
const photo = await SlateManager.getRandomSlateElementURL({
id: Environment.AVATAR_SLATE_ID,
fallback:
"https://slate.textile.io/ipfs/bafkreick3nscgixwfpq736forz7kzxvvhuej6kszevpsgmcubyhsx2pf7i",
});
const user = await Data.createUser({
username: newUsername,
email: newEmail,
twitterId: twitterUser.id_str,
data: {
photo,
photo: "",
body: "",
settings: {
settings_deals_auto_approve: false,

View File

@ -76,19 +76,13 @@ export default async (req, res) => {
.send({ decorator: "SERVER_CREATE_USER_BUCKET_INIT_FAILURE", error: true });
}
const photo = await SlateManager.getRandomSlateElementURL({
id: Environment.AVATAR_SLATE_ID,
fallback:
"https://slate.textile.io/ipfs/bafkreick3nscgixwfpq736forz7kzxvvhuej6kszevpsgmcubyhsx2pf7i",
});
const user = await Data.createUser({
password: hash,
salt,
username: newUsername,
email: newEmail,
data: {
photo,
photo: "",
body: "",
settings: {
settings_deals_auto_approve: false,

View File

@ -17,7 +17,7 @@ import { ConfirmationModal } from "~/components/core/ConfirmationModal";
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
import ScenePage from "~/components/core/ScenePage";
import ScenePageHeader from "~/components/core/ScenePageHeader";
import Avatar from "~/components/core/Avatar";
import ProfilePhoto from "~/components/core/ProfilePhoto";
const STYLES_FILE_HIDDEN = css`
height: 1px;
@ -198,7 +198,11 @@ export default class SceneEditAccount extends React.Component {
<div>
<div css={STYLES_HEADER}>Your Avatar</div>
<Avatar size={256} url={this.props.viewer.data.photo} />
<ProfilePhoto
size={256}
photo={this.props.viewer.data.photo}
userId={this.props.viewer.id}
/>
<div style={{ marginTop: 24 }}>
<input