mirror of
https://github.com/filecoin-project/slate.git
synced 2024-11-22 21:45:56 +03:00
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:
parent
b10accf732
commit
d73be6a91d
@ -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>
|
||||
|
@ -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}>
|
||||
|
81
components/core/ProfilePhoto.js
Normal file
81
components/core/ProfilePhoto.js
Normal 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} />
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
@ -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 ? (
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user