mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 10:34:17 +00:00
rework account layout style
This commit is contained in:
parent
4856882d71
commit
35c2944d40
@ -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>
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user