reimplement account style

This commit is contained in:
srgooglo 2022-03-15 04:24:48 +01:00
parent fbb1f9a62b
commit 79231d2c6a
2 changed files with 191 additions and 87 deletions

View File

@ -1,10 +1,10 @@
import React from "react" import React from "react"
import * as antd from "antd" import * as antd from "antd"
import { Translation } from "react-i18next" import classnames from "classnames"
import moment from "moment" import moment from "moment"
import { Icons } from "components/Icons" import { Icons } from "components/Icons"
import { Skeleton, PostsFeed, FollowButton } from "components" import { Skeleton, PostsFeed, FollowButton, FollowersList } from "components"
import { Session, User } from "models" import { Session, User } from "models"
import "./index.less" import "./index.less"
@ -13,6 +13,9 @@ export default class Account extends React.Component {
static bindApp = ["userController", "sessionController"] static bindApp = ["userController", "sessionController"]
state = { state = {
transitionActive: false,
activeKey: "posts",
isSelf: false, isSelf: false,
isFollowed: false, isFollowed: false,
user: null, user: null,
@ -44,17 +47,18 @@ export default class Account extends React.Component {
if (!isSelf) { if (!isSelf) {
const followedResult = await this.api.get.isFollowed(undefined, { user_id: user._id }).catch(() => false) const followedResult = await this.api.get.isFollowed(undefined, { user_id: user._id }).catch(() => false)
const followersResult = await this.api.get.followers(undefined, { user_id: user._id }).catch(() => false)
if (followedResult) { if (followedResult) {
isFollowed = followedResult.isFollowed isFollowed = followedResult.isFollowed
} }
}
const followersResult = await this.api.get.followers(undefined, { user_id: user._id }).catch(() => false)
if (followersResult) { if (followersResult) {
followers = followersResult followers = followersResult
} }
} }
}
await this.setState({ await this.setState({
isSelf, isSelf,
@ -92,6 +96,28 @@ export default class Account extends React.Component {
}) })
} }
handlePageTransition = (key) => {
if (this.state.activeKey === key) {
return false
}
this.setState({
transitionActive: true,
})
setTimeout(() => {
this.setState({
activeKey: key
})
setTimeout(() => {
this.setState({
transitionActive: false,
})
}, 100)
}, 100)
}
render() { render() {
const user = this.state.user const user = this.state.user
@ -99,22 +125,68 @@ export default class Account extends React.Component {
return <Skeleton /> return <Skeleton />
} }
const createdAtYear = moment(new Date(Number(user.createdAt))).format("YYYY")
return ( return (
<div className="accountProfile"> <div className="accountProfile">
<div className="card"> {user.cover && <div className="cover" style={{ backgroundImage: `url("${user.cover}")` }} />}
<div className="header"> <div className="profileCard">
<div className="user"> <div className="basicData">
<div> <div className="title">
<div className="field">
<div className="avatar">
<img src={user.avatar} /> <img src={user.avatar} />
</div> </div>
<div>
<div>
<h1>{user.fullName ?? user.username}</h1>
<span>@{user.username}</span>
</div> </div>
<div className="field">
<div>
<h1>{user.fullName ?? user.username}</h1>
{user.verified && <Icons.verifiedBadge />}
</div>
<span>@{user.username}</span>
</div>
</div>
{!this.state.isSelf && <div>
<FollowButton
count={this.state.followers.length}
onClick={this.onClickFollow}
followed={this.state.isFollowed}
/>
</div>}
</div>
<div className="description">
<p>
{user.description}
</p>
</div>
</div>
<antd.Tabs
className="tabs"
type="card"
activeKey={this.state.activeKey}
onTabClick={this.handlePageTransition}
destroyInactiveTabPane
>
<antd.Tabs.TabPane tab={<Icons.Inbox />} key="posts">
<div className={classnames("fade-opacity-active", { "fade-opacity-leave": this.state.transitionActive })}>
<div className="posts">
<PostsFeed
fromUserId={user._id}
/>
</div>
</div>
</antd.Tabs.TabPane>
<antd.Tabs.TabPane tab={<Icons.Users />} key="followers">
<div className={classnames("fade-opacity-active", { "fade-opacity-leave": this.state.transitionActive })}>
<FollowersList
followers={this.state.followers}
/>
</div>
</antd.Tabs.TabPane>
<antd.Tabs.TabPane tab={<Icons.Info />} key="details">
<div className={classnames("fade-opacity-active", { "fade-opacity-leave": this.state.transitionActive })}>
<div id="statistics" className="statistics"> <div id="statistics" className="statistics">
<div> <div>
<span><Icons.Users /> {this.state.followers.length} Followers</span> <span><Icons.Users /> {this.state.followers.length} Followers</span>
@ -123,34 +195,12 @@ export default class Account extends React.Component {
<span><Icons.FileText /> 0 Posts</span> <span><Icons.FileText /> 0 Posts</span>
</div> </div>
<div> <div>
<span>Joined at {createdAtYear}</span> <span>Joined at {moment(new Date(Number(user.createdAt))).format("YYYY")}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </antd.Tabs.TabPane>
</antd.Tabs>
{!this.state.isSelf && <div>
<FollowButton
onClick={this.onClickFollow}
followed={this.state.isFollowed}
/>
</div>}
</div>
<div className="extension">
<div className="badgesList">
{user.badges.map((role, index) => {
return <antd.Tag>{role}</antd.Tag>
})}
</div>
</div>
</div>
<div className="posts">
<PostsFeed
fromUserId={user._id}
/>
</div>
</div> </div>
) )
} }

View File

@ -1,67 +1,89 @@
@borderColor : #dddddd;
@borderRadius: 12px; @borderRadius: 12px;
.accountProfile { .accountProfile {
.card { padding: 0 20px;
display : flex;
flex-direction: column;
color : var(--background-color-contrast);
h1, .cover {
h2, z-index : 50;
h3, position : relative;
h4, border-radius: @borderRadius @borderRadius 0 0;
h5,
h6, outline: 1px solid var(--border-color);
span { content: "";
color: var(--background-color-contrast);
width: 100%;
background-position: center;
background-size : cover;
height: 18vh;
transform: translate(0, 10px);
} }
.header { .profileCard {
z-index : 51;
position: relative; position: relative;
display : inline-flex;
align-items : center; display : flex;
justify-content: space-between; flex-direction: column;
z-index: 15;
width : 100%;
padding: 12px 24px;
font-family: "Roboto Mono", monospace;
color : var(--background-color-contrast); color : var(--background-color-contrast);
background-color: var(--background-color-primary);
border : 1px solid var(--border-color); border : 1px solid var(--border-color);
border-radius: @borderRadius; border-radius: @borderRadius;
word-break: break-all; padding: 20px 15px;
.user { .basicData {
display: inline-flex; display : inline-flex;
flex-direction: row; flex-direction : row;
justify-content: space-between;
> div { margin-bottom: 15px;
align-self: flex-start;
margin-right: 15px;
> div {
margin-bottom: 5px;
}
}
.avatar {
img { img {
width : 70px; width : 70px;
height: 70px; height : 70px;
border-radius: 4px; border-radius: 4px;
} }
}
svg {
fill: var(--appColor);
}
.title {
display : inline-flex;
flex-direction: row;
align-items : center;
}
.field {
display : inline-flex;
flex-direction: column;
margin-right: 15px;
h1 { h1 {
margin : 0; margin: 0;
font-size: 35px; font-size : 35px;
line-height: 37px; line-height: 37px;
} }
>div {
display: inline-flex;
}
}
}
.description {
p {
word-break: break-all;
margin : 0;
} }
} }
@ -84,9 +106,41 @@
border-radius: 0 0 @borderRadius @borderRadius; border-radius: 0 0 @borderRadius @borderRadius;
} }
h1,
h2,
h3,
h4,
h5,
h6,
span,
p {
user-select: text;
}
} }
>div { .tabs {
margin-bottom: 10px; .ant-tabs-nav {
margin: 0 30px 20px 30px;
}
.ant-tabs-nav::before {
border: none !important;
}
.ant-tabs-tab {
padding : 8px 20px !important;
border-color : var(--border-color) !important;
margin-right : 20px !important;
background-color: var(--background-color-primary) !important;
border-top : 0 !important;
border-radius : 0 0 4px 4px !important;
svg {
font-size: 1rem;
margin : 0 !important;
}
}
} }
} }