rework account layout style

This commit is contained in:
SrGooglo 2023-01-06 18:15:38 +00:00
parent 4856882d71
commit 35c2944d40
2 changed files with 138 additions and 298 deletions

View File

@ -1,12 +1,11 @@
import React from "react"
import * as antd from "antd"
import classnames from "classnames"
import Loadable from "react-loadable"
import { Translation } from "react-i18next"
import { Icons, createIconRender } from "components/Icons"
import { Image, Skeleton, FollowButton } from "components"
import { Session, User } from "models"
import { Icons } from "components/Icons"
import { Skeleton, FollowButton, UserCard } from "components"
import { Session } from "models"
import DetailsTab from "./tabs/details"
import PostsTab from "./tabs/posts"
@ -52,35 +51,6 @@ const TabRender = React.memo((props, ref) => {
</div>
})
const UserBadges = React.memo((props) => {
return React.createElement(Loadable({
loader: async () => {
let { user_id } = props
const badgesData = await User.getUserBadges(user_id).catch((err) => {
console.error(err)
app.message.error("Failed to fetch user badges")
return null
})
if (!badgesData) {
return null
}
return () => badgesData.map((badge, index) => {
return <antd.Tooltip placement="bottom" title={badge.description ?? "An badge"}>
<antd.Tag color={badge.color ?? "default"} key={index} id={badge.name} icon={createIconRender(badge.icon)} className="badge">
<span>{badge.label}</span>
</antd.Tag>
</antd.Tooltip>
})
},
loading: antd.Skeleton,
}))
})
export default class Account extends React.Component {
state = {
requestedUser: null,
@ -100,7 +70,9 @@ export default class Account extends React.Component {
coverComponent = React.createRef()
tabNavigatorRef = React.createRef()
leftPanelRef = React.createRef()
actionsRef = React.createRef()
api = window.app.api.withEndpoints("main")
@ -131,6 +103,8 @@ export default class Account extends React.Component {
return false
}
console.log(`Loaded User [${user.username}] >`, user)
if (!isSelf) {
const followedResult = await this.api.get.isFollowed(undefined, { user_id: user._id }).catch(() => false)
@ -154,11 +128,25 @@ export default class Account extends React.Component {
followers,
})
app.eventBus.emit("style.compactMode", true)
// create intersection observer for cover
this.coverIntersectionObserver = new IntersectionObserver((e) => {
if (e[0].intersectionRatio > 0) {
this.leftPanelRef.current.style.transform = "translate(0, -100px)"
this.actionsRef.current.style.opacity = "1"
} else {
this.leftPanelRef.current.style.transform = "translate(0, 0)"
this.actionsRef.current.style.opacity = "0"
}
}, {
root: document.querySelector("#root"),
threshold: 0
})
this.coverIntersectionObserver.observe(this.coverComponent.current)
}
componentWillUnmount = () => {
app.eventBus.emit("style.compactMode", false)
this.coverIntersectionObserver.disconnect()
}
fetchData = async (username) => {
@ -210,29 +198,6 @@ export default class Account extends React.Component {
})
}
handleScroll = (e) => {
if (!this.state.user?.cover) {
return false
}
// if component scrolled foward set cover height to 0
if (e.target.scrollTop > 0) {
this.coverComponent.current.style.height = "0px"
if (window.isMobile) {
this.tabNavigatorRef.current.style.overflow = "hidden"
this.tabNavigatorRef.current.style.height = "0px"
}
} else {
this.coverComponent.current.style.height = ""
if (window.isMobile) {
this.tabNavigatorRef.current.style.overflow = ""
this.tabNavigatorRef.current.style.height = ""
}
}
}
render() {
const user = this.state.user
@ -249,65 +214,55 @@ export default class Account extends React.Component {
return <Skeleton />
}
return <div className="accountProfile">
{user.cover && <div
className={classnames("cover", {
["expanded"]: this.state.coverExpanded
})}
ref={this.coverComponent}
style={{ backgroundImage: `url("${user.cover}")` }}
onClick={() => this.toogleCoverExpanded()}
/>}
<div className="profileCardWrapper">
<div className="profileCard">
<div className="basicData">
<div className="title">
<div className="field">
<div className="avatar">
<Image
alt="ProfileImage"
src={user.avatar}
/>
</div>
</div>
return <div
className="accountProfile"
id="profile"
>
{
user.cover && <div
className={classnames("cover", {
["expanded"]: this.state.coverExpanded
})}
ref={this.coverComponent}
style={{ backgroundImage: `url("${user.cover}")` }}
onClick={() => this.toogleCoverExpanded()}
id="profile-cover"
/>
}
<div className="field">
<div>
<h1>{user.fullName ?? user.username}</h1>
{user.verified && <Icons.verifiedBadge />}
</div>
<div className="panels">
<div
className="leftPanel"
ref={this.leftPanelRef}
>
<UserCard
user={user}
/>
<span>@{user.username}</span>
</div>
</div>
<div>
<FollowButton
count={this.state.followers.length}
onClick={this.onClickFollow}
followed={this.state.isFollowed}
self={this.state.isSelf}
/>
</div>
<div
className="actions"
ref={this.actionsRef}
>
<FollowButton
count={this.state.followers.length}
onClick={this.onClickFollow}
followed={this.state.isFollowed}
self={this.state.isSelf}
/>
</div>
<div className="description">
<p>
{user.description}
</p>
</div>
</div>
<div className="badgesTab">
<React.Suspense fallback={<antd.Skeleton />}>
<UserBadges user_id={user._id} />
</React.Suspense>
<div
className="content"
ref={this.contentRef}
>
<TabRender
renderKey={this.state.tabActiveKey}
state={this.state}
/>
</div>
</div>
<div className="contents">
<div className="tabMenuWrapper" ref={this.tabNavigatorRef}>
<div className="tabMenuWrapper">
<antd.Menu
className="tabMenu"
mode={window.isMobile ? "horizontal" : "vertical"}
@ -342,13 +297,6 @@ export default class Account extends React.Component {
</antd.Menu.Item>
</antd.Menu>
</div>
<div className="tabContent" ref={this.contentRef} onScroll={this.handleScroll}>
<TabRender
renderKey={this.state.tabActiveKey}
state={this.state}
/>
</div>
</div>
</div>
}

View File

@ -1,208 +1,107 @@
@borderRadius: 12px;
.accountProfile {
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
overflow: hidden;
padding: 10px 20px;
// max-width: 70vw;
// min-width: 900px;
transition: all 0.3s ease-in-out;
height: 100%;
.cover {
z-index: 50;
position: relative;
border-radius: @borderRadius @borderRadius 0 0;
outline: 1px solid var(--border-color);
border-radius: @borderRadius;
content: "";
width: 100%;
height: 25vh;
margin-bottom: 10px;
background-position: center;
background-size: cover;
height: 25vh;
transform: translate(0, 10px);
transition: all 0.3s ease-in-out;
&.expanded {
height: 70vh;
transform: translate(0, 0);
background-size: cover;
background-repeat: no-repeat;
border-radius: @borderRadius;
margin-bottom: 10px;
}
}
.profileCardWrapper {
position: sticky;
top: 0;
z-index: 150;
}
.profileCard {
.panels {
position: relative;
z-index: 150;
display: flex;
flex-direction: column;
color: var(--background-color-contrast);
background-color: var(--background-color-primary);
border: 1px solid var(--border-color);
border-radius: @borderRadius @borderRadius 0 @borderRadius;
padding: 20px 15px;
height: 15vh;
min-height: 175px;
.basicData {
display: inline-flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 15px;
.avatar {
width: 100px;
height: 100px;
img {
width: 100%;
height: 100%;
border-radius: 8px;
}
}
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 {
margin: 0;
font-size: 35px;
line-height: 37px;
}
>div {
display: inline-flex;
}
}
}
.description {
max-height: 5vh;
overflow: hidden;
p {
height: 100%;
overflow: hidden;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
margin: 0;
}
}
h1,
h2,
h3,
h4,
h5,
h6,
span,
p {
user-select: text;
}
}
.badgesTab {
position: relative;
z-index: 140;
display: flex;
flex-direction: row;
padding: 30px 10px 10px 10px;
background-color: var(--background-color-accent);
border-radius: 0 0 @borderRadius @borderRadius;
transform: translate(0, -20px);
border: 1px solid var(--border-color);
.badge {
margin-left: 10px;
height: fit-content;
}
}
.tabMenuWrapper {
position: sticky !important;
top: 20px;
height: fit-content;
.tabMenu {
width: fit-content;
min-width: 10vw;
padding: 10px;
background-color: var(--background-color-accent) !important;
border-radius: @borderRadius;
}
}
.contents {
display: grid;
grid-template-columns: 10vw 1fr 10vw;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 1fr;
grid-column-gap: 50px;
grid-column-gap: 20px;
grid-row-gap: 0px;
width: 100%;
height: 100%;
padding-top: 20px;
overflow: hidden;
overflow-y: hidden;
margin-top: -1.5vh;
transition: all 0.3s ease-in-out;
.tabContent {
.leftPanel {
position: sticky;
border-radius: @borderRadius;
top: 0;
padding: 20px 10px 20vh 10px;
z-index: 55;
overflow-y: overlay;
display: flex;
flex-direction: column;
align-items: center;
transition: all 0.3s ease-in-out;
.userCard {
position: sticky;
top: 0;
z-index: 55;
}
.actions {
display: flex;
flex-direction: column;
height: fit-content;
width: 20vw;
min-width: 400px;
padding: 20px;
margin-top: 20px;
background-color: var(--background-color-accent);
border-radius: 12px;
transition: all 0.3s ease-in-out;
.followButton {
width: fit-content;
}
}
}
.tabMenuWrapper {
position: sticky;
top: 0;
display: flex;
flex-direction: column;
background-color: var(--background-color-accent);
border-radius: 12px;
padding: 20px;
height: fit-content;
width: 20vw;
min-width: 400px;
justify-self: center;
}
}
@ -210,18 +109,11 @@
background-color: var(--background-color-accent);
padding: 20px;
border-radius: @borderRadius;
}
font-family: "DM Mono", monospace;
h1,
h2,
h3,
h4,
h5,
h6,
p,
span {
user-select: text;
}
.followersList {
background-color: var(--background-color-accent);
padding: 20px;
border-radius: @borderRadius;
}
}