From d14af06f0941718102d183ddea7073417fdfa711 Mon Sep 17 00:00:00 2001 From: srgooglo Date: Thu, 8 Sep 2022 16:52:54 +0200 Subject: [PATCH] improve `account` page --- packages/app/src/pages/account/index.jsx | 193 +++++++++++------- packages/app/src/pages/account/index.less | 163 ++++++++------- .../app/src/pages/account/tabs/details.jsx | 43 ++++ .../app/src/pages/account/tabs/followers.jsx | 9 + packages/app/src/pages/account/tabs/posts.jsx | 11 + 5 files changed, 273 insertions(+), 146 deletions(-) create mode 100644 packages/app/src/pages/account/tabs/details.jsx create mode 100644 packages/app/src/pages/account/tabs/followers.jsx create mode 100644 packages/app/src/pages/account/tabs/posts.jsx diff --git a/packages/app/src/pages/account/index.jsx b/packages/app/src/pages/account/index.jsx index dd006990..b340f73a 100644 --- a/packages/app/src/pages/account/index.jsx +++ b/packages/app/src/pages/account/index.jsx @@ -1,40 +1,22 @@ import React from "react" import * as antd from "antd" import classnames from "classnames" -import moment from "moment" +import Loadable from "react-loadable" import { Icons } from "components/Icons" -import { Image, Skeleton, PostsFeed, FollowButton, FollowersList } from "components" +import { Image, Skeleton, FollowButton } from "components" import { Session, User } from "models" +import DetailsTab from "./tabs/details" +import PostsTab from "./tabs/posts" +import FollowersTab from "./tabs/followers" + import "./index.less" const TabsComponent = { - "posts": React.memo((props) => { - return
- -
- }), - "followers": React.memo((props) => { - return - }), - "details": React.memo((props) => { - return
-
- {props.state.followers.length} Followers -
-
- 0 Posts -
-
- Joined at {moment(new Date(Number(props.state.user.createdAt))).format("YYYY")} -
-
- }) + "posts": PostsTab, + "followers": FollowersTab, + "details": DetailsTab } const TabRender = React.memo((props) => { @@ -56,7 +38,7 @@ const TabRender = React.memo((props) => { const Tab = TabsComponent[activeKey] if (!Tab) { - return

Nothing to see here...

+ return null } return
@@ -64,7 +46,33 @@ const TabRender = React.memo((props) => {
}) -// TODO: profileCard scroll effect (Hide description and wrap with entire body when cover image is not visible) +const UserBadges = React.memo((props) => { + return React.createElement(Loadable({ + loader: async () => { + let { badges } = props + + if (!badges || Array.isArray(badges) === false || badges.length === 0) { + return null + } + + // fetch badges datam from api + const badgesData = await app.api.request("main", "get", "badges", { + _id: badges + }).catch(() => false) + + if (!badgesData) { + return null + } + + return () => badgesData.map((badge, index) => { + return + {badge.label} + + }) + }, + loading: antd.Skeleton, + })) +}) export default class Account extends React.Component { state = { @@ -82,6 +90,8 @@ export default class Account extends React.Component { isNotExistent: false, } + coverComponent = React.createRef() + api = window.app.api.withEndpoints("main") componentDidMount = async () => { @@ -135,6 +145,13 @@ export default class Account extends React.Component { isFollowed, followers, }) + + // + app.eventBus.emit("style.compactMode", true) + } + + componentWillUnmount = () => { + app.eventBus.emit("style.compactMode", false) } fetchData = async (username) => { @@ -180,6 +197,15 @@ export default class Account extends React.Component { }) } + handleScroll = (e) => { + // if component scrolled foward set cover height to 0 + if (e.target.scrollTop > 0) { + this.coverComponent.current.style.height = "0px" + } else { + this.coverComponent.current.style.height = "" + } + } + render() { const user = this.state.user @@ -197,59 +223,82 @@ export default class Account extends React.Component { } return
- {user.cover &&
} -
-
-
-
-
- ProfileImage + {user.cover &&
} +
+
+
+
+
+
+ ProfileImage +
+
+ +
+
+

{user.fullName ?? user.username}

+ {user.verified && } +
+ + @{user.username}
-
-
-

{user.fullName ?? user.username}

- {user.verified && } -
- - @{user.username} -
+ {!this.state.isSelf &&
+ +
} +
+ +
+

+ {user.description} +

- {!this.state.isSelf &&
- -
}
-
-

- {user.description} -

-
- -
- key.toTitleCase())} - value={this.state.tabActiveKey.toTitleCase()} - onChange={this.handlePageTransition} - /> +
+ }> + +
-
- +
+
+ this.handlePageTransition(e.key)} + > + + Posts + + + + Followers + + + + Details + + +
+ +
+ +
} diff --git a/packages/app/src/pages/account/index.less b/packages/app/src/pages/account/index.less index fab80b78..778105a2 100644 --- a/packages/app/src/pages/account/index.less +++ b/packages/app/src/pages/account/index.less @@ -2,11 +2,17 @@ .accountProfile { width: 100%; - height: 100%; + height: 100vh; + + overflow: hidden; + + padding: 10px 20px; // max-width: 70vw; // min-width: 900px; + transition: all 0.3s ease-in-out; + .cover { z-index: 50; position: relative; @@ -23,13 +29,18 @@ height: 25vh; transform: translate(0, 10px); + transition: all 0.3s ease-in-out; + } + + .profileCardWrapper { + position: sticky; + top: 0; + z-index: 150; } .profileCard { - position: sticky; - top: 0; - - z-index: 151; + position: relative; + z-index: 150; display: flex; flex-direction: column; @@ -42,6 +53,8 @@ padding: 20px 15px; + height: 15vh; + .basicData { display: inline-flex; flex-direction: row; @@ -90,53 +103,21 @@ } .description { + max-height: 5vh; + overflow: hidden; + p { - word-break: break-all; + height: 100%; + overflow: hidden; + + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + margin: 0; } } - .extension { - position: relative; - display: inline-flex; - - top: -10px; - width: 100%; - padding: 19px 10px 10px 10px; - - border-top: 0; - border-right: 0; - - border-style: solid; - border-width: 1px; - - border-color: var(--border-color); - border-top-color: transparent; - - border-radius: 0 0 @borderRadius @borderRadius; - } - - .switchTab { - position: absolute; - bottom: 0; - right: -1px; - - border: 1px solid var(--border-color); - border-top: none; - - transform: translate(0, 33px); - background-color: var(--background-color-primary); - border-radius: 0 0 8px 8px; - - // .ant-segmented { - // background-color: transparent; - // } - - // .ant-segmented-item-selected { - // background-color: var(--background-color-accent)!important; - // } - } - h1, h2, h3, @@ -149,45 +130,79 @@ } } - .tabContent { - margin-top: 45px; + .badgesTab { + position: relative; + z-index: 140; + + height: 5vh; + + 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; + } } - .tabs { - transform: translate(0, -20px); - position: relative; - z-index: 55; + .tabMenuWrapper { + position: sticky!important; + top: 20px; - .ant-tabs-nav-wrap { - justify-content: flex-end; + height: fit-content; + + .tabMenu { + width: fit-content; + min-width: 10vw; + + padding: 10px; + background-color: var(--background-color-accent) !important; + border-radius: @borderRadius; } + } - .ant-tabs-nav { - margin: 0 20px 20px 0; + .contents { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-template-rows: 1fr; + grid-column-gap: 10px; + grid-row-gap: 0px; - z-index: 152; + width: 100%; + height: 100vh; + + overflow: hidden; + overflow-y: overlay; + margin-top: -1.5vh; + + .tabContent { position: sticky; - top: 0; + border-radius: @borderRadius; + + top: -20vh; + padding: 20px 10px 20vh 10px; } + } - .ant-tabs-nav::before { - border: none !important; - } + .details { + background-color: var(--background-color-accent); + padding: 20px; + border-radius: @borderRadius; - .ant-tabs-tab { - margin-right: 20px !important; - padding: 8px 20px !important; + font-family: "DM Mono", monospace; - border-color: var(--border-color) !important; - background-color: var(--background-color-primary) !important; - - border-radius: 4px !important; - - svg { - font-size: 1rem; - margin: 0 !important; - } + h1,h2,h3,h4,h5,h6,p,span { + user-select: text; } } } \ No newline at end of file diff --git a/packages/app/src/pages/account/tabs/details.jsx b/packages/app/src/pages/account/tabs/details.jsx new file mode 100644 index 00000000..cc8317dc --- /dev/null +++ b/packages/app/src/pages/account/tabs/details.jsx @@ -0,0 +1,43 @@ +import React from "react" +import moment from "moment" + +import { Icons } from "components/Icons" + +export default React.memo((props) => { + return
+ {props.state.user.fullName && +
+

{props.state.user.fullName}

+
+ } +
+

+ @{props.state.user.username} #{props.state.user._id} +

+
+ {props.state.user.description && +
+

+ {props.state.user.description} +

+
+ } + { + props.state.user.roles.includes("admin") && +
+ Administrators Team +
+ } +
+ {props.state.followers.length} Followers +
+ {props.state.user?.badges.length > 0 && +
+ {props.state.user?.badges.length} Badges collected +
+ } +
+ Joined at {moment(new Date(Number(props.state.user.createdAt))).format("YYYY")} +
+
+}) \ No newline at end of file diff --git a/packages/app/src/pages/account/tabs/followers.jsx b/packages/app/src/pages/account/tabs/followers.jsx new file mode 100644 index 00000000..54312a27 --- /dev/null +++ b/packages/app/src/pages/account/tabs/followers.jsx @@ -0,0 +1,9 @@ +import React from "react" + +import { FollowersList } from "components" + +export default React.memo((props) => { + return +}) \ No newline at end of file diff --git a/packages/app/src/pages/account/tabs/posts.jsx b/packages/app/src/pages/account/tabs/posts.jsx new file mode 100644 index 00000000..4e028e43 --- /dev/null +++ b/packages/app/src/pages/account/tabs/posts.jsx @@ -0,0 +1,11 @@ +import React from "react" + +import { PostsFeed } from "components" + +export default React.memo((props) => { + return
+ +
+}) \ No newline at end of file