mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
use like logic
This commit is contained in:
parent
914655ecd6
commit
e7561c06c8
@ -1,62 +1,19 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import * as antd from "antd"
|
import * as antd from "antd"
|
||||||
import { Icons } from "components/Icons"
|
import { Icons } from "components/Icons"
|
||||||
import classnames from "classnames"
|
import { LikeButton } from "components"
|
||||||
import moment from "moment"
|
import moment from "moment"
|
||||||
|
import classnames from "classnames"
|
||||||
|
|
||||||
import { User } from "models"
|
import { User } from "models"
|
||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
function LikeButton(props) {
|
function PostHeader(props) {
|
||||||
const [liked, setLiked] = React.useState(props.defaultLiked ?? false)
|
|
||||||
const [clicked, setCliked] = React.useState(false)
|
|
||||||
|
|
||||||
const handleClick = async () => {
|
|
||||||
let to = !liked
|
|
||||||
|
|
||||||
setCliked(to)
|
|
||||||
|
|
||||||
if (typeof props.onClick === "function") {
|
|
||||||
const result = await props.onClick(to)
|
|
||||||
if (typeof result === "boolean") {
|
|
||||||
to = result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setLiked(to)
|
|
||||||
}
|
|
||||||
|
|
||||||
return <button
|
|
||||||
className={classnames("likeButton", { ["clicked"]: liked })}
|
|
||||||
onClick={handleClick}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classnames(
|
|
||||||
"ripple",
|
|
||||||
{ ["clicked"]: clicked }
|
|
||||||
)}
|
|
||||||
></div>
|
|
||||||
<svg
|
|
||||||
className={classnames(
|
|
||||||
"heart",
|
|
||||||
{ ["empty"]: !liked },
|
|
||||||
{ ["clicked"]: clicked },
|
|
||||||
)}
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path d="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
|
|
||||||
function PostHeader({ postData }) {
|
|
||||||
const [timeAgo, setTimeAgo] = React.useState(0)
|
const [timeAgo, setTimeAgo] = React.useState(0)
|
||||||
|
|
||||||
const updateTimeAgo = () => {
|
const updateTimeAgo = () => {
|
||||||
setTimeAgo(moment(postData.created_at ?? "").fromNow())
|
setTimeAgo(moment(props.postData.created_at ?? "").fromNow())
|
||||||
}
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -69,21 +26,31 @@ function PostHeader({ postData }) {
|
|||||||
return () => {
|
return () => {
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
}
|
}
|
||||||
}, [postData.created_at])
|
}, [props.postData.created_at])
|
||||||
|
|
||||||
return <div className="userInfo">
|
return <div className="postHeader">
|
||||||
<div className="avatar">
|
<div className="userInfo">
|
||||||
<antd.Avatar src={postData.user?.avatar} />
|
<div className="avatar">
|
||||||
</div>
|
<antd.Avatar src={props.postData.user?.avatar} />
|
||||||
<div className="info">
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
{postData.user?.fullName ?? `@${postData.user?.username}`}
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="info">
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
{props.postData.user?.fullName ?? `@${props.postData.user?.username}`}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{timeAgo}
|
{timeAgo}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="postHeaderActions">
|
||||||
|
<div className="item" onClick={props.onClickLike}>
|
||||||
|
{props.isLiked && <Icons.Heart id="likeIndicator" />}
|
||||||
|
</div>
|
||||||
|
<div className="item" onClick={props.onClickSave}>
|
||||||
|
<Icons.Bookmark />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -91,8 +58,8 @@ function PostHeader({ postData }) {
|
|||||||
|
|
||||||
function PostContent({ message }) {
|
function PostContent({ message }) {
|
||||||
return <div className="content">
|
return <div className="content">
|
||||||
{message}
|
{message}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
function PostActions(props) {
|
function PostActions(props) {
|
||||||
@ -147,7 +114,6 @@ export default class PostCard extends React.Component {
|
|||||||
|
|
||||||
await this.setState({
|
await this.setState({
|
||||||
selfId,
|
selfId,
|
||||||
likes: this.props.data.likes,
|
|
||||||
loading: false
|
loading: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -166,30 +132,49 @@ export default class PostCard extends React.Component {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClickSave = async () => {
|
||||||
|
// TODO: save post
|
||||||
|
}
|
||||||
|
|
||||||
hasLiked = () => {
|
hasLiked = () => {
|
||||||
return this.props.data.likes.some(user_id => user_id === this.state.selfId)
|
return this.state.data.likes.some(user_id => user_id === this.state.selfId)
|
||||||
|
}
|
||||||
|
|
||||||
|
isSelf = () => {
|
||||||
|
return this.state.selfId === this.state.data.user._id
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const defaultLiked = this.hasLiked()
|
const hasLiked = this.hasLiked()
|
||||||
|
|
||||||
if (this.state.loading) {
|
if (this.state.loading) {
|
||||||
return <antd.Skeleton active />
|
return <antd.Skeleton active />
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div id={this.props.data._id} key={this.props.data._id} className="postCard">
|
return <div
|
||||||
|
id={this.props.data._id}
|
||||||
|
key={this.props.data._id}
|
||||||
|
className={classnames("postCard", { ["liked"]: hasLiked })}
|
||||||
|
>
|
||||||
<div className="wrapper">
|
<div className="wrapper">
|
||||||
<PostHeader
|
<PostHeader
|
||||||
postData={this.props.data}
|
postData={this.props.data}
|
||||||
|
isLiked={hasLiked}
|
||||||
|
onClickLike={() => this.onClickLike(false)}
|
||||||
|
onClickSave={this.onClickSave}
|
||||||
/>
|
/>
|
||||||
<PostContent
|
<PostContent
|
||||||
message={this.props.data.message}
|
message={this.props.data.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="actionsIndicator">
|
||||||
|
<Icons.MoreHorizontal />
|
||||||
|
</div>
|
||||||
<div className="actionsWrapper">
|
<div className="actionsWrapper">
|
||||||
<PostActions
|
<PostActions
|
||||||
onClickLike={this.onClickLike}
|
onClickLike={this.onClickLike}
|
||||||
defaultLiked={defaultLiked}
|
defaultLiked={hasLiked}
|
||||||
|
isSelf={this.isSelf()}
|
||||||
likes={this.state.data.likes.length}
|
likes={this.state.data.likes.length}
|
||||||
comments={this.state.data.comments.length}
|
comments={this.state.data.comments.length}
|
||||||
/>
|
/>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
width : 100%;
|
width : 100%;
|
||||||
max-width: 40vw;
|
max-width: 600px;
|
||||||
|
|
||||||
filter: drop-shadow(3px 3px 2px #c5c5c5);
|
filter: drop-shadow(3px 3px 2px #c5c5c5);
|
||||||
|
|
||||||
@ -12,6 +12,29 @@
|
|||||||
|
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
|
|
||||||
|
outline-width: 1px;
|
||||||
|
outline-style: solid;
|
||||||
|
outline-color: transparent;
|
||||||
|
|
||||||
|
&.liked {
|
||||||
|
filter: drop-shadow(0px 0px 2px var(--primaryColor));
|
||||||
|
|
||||||
|
//outline-color: ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actionsIndicator {
|
||||||
|
display : flex;
|
||||||
|
flex-direction : row;
|
||||||
|
align-items : center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
width : 100%;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
font-size: 18px;
|
||||||
|
color : var(--background-color-contrast);
|
||||||
|
}
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
display : inline-flex;
|
display : inline-flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -22,35 +45,56 @@
|
|||||||
|
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
|
|
||||||
.userInfo {
|
.postHeader {
|
||||||
display : inline-flex;
|
display : inline-flex;
|
||||||
flex-direction: row;
|
flex-direction : row;
|
||||||
align-items : center;
|
justify-content: space-between;
|
||||||
|
|
||||||
margin-bottom: 15px;
|
.userInfo {
|
||||||
|
display : inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items : center;
|
||||||
|
|
||||||
>div {
|
margin-bottom: 15px;
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
display : inline-flex;
|
|
||||||
flex-direction : column;
|
|
||||||
align-items : center;
|
|
||||||
justify-content: start;
|
|
||||||
|
|
||||||
text-align: start;
|
|
||||||
|
|
||||||
width: fit-content;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin : 0;
|
|
||||||
font-family: "DM Mono", monospace;
|
|
||||||
align-self : start;
|
|
||||||
}
|
|
||||||
|
|
||||||
>div {
|
>div {
|
||||||
align-self: start;
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display : inline-flex;
|
||||||
|
flex-direction : column;
|
||||||
|
align-items : center;
|
||||||
|
justify-content: start;
|
||||||
|
|
||||||
|
text-align: start;
|
||||||
|
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin : 0;
|
||||||
|
font-family: "DM Mono", monospace;
|
||||||
|
align-self : start;
|
||||||
|
}
|
||||||
|
|
||||||
|
>div {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.postHeaderActions {
|
||||||
|
display : inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size : 16px;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#likeIndicator {
|
||||||
|
color: var(--primaryColor);
|
||||||
|
fill : var(--primaryColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,9 +104,10 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items : flex-start;
|
align-items : flex-start;
|
||||||
|
|
||||||
background-color: var(--background-color-primary);
|
//background-color: var(--background-color-primary);
|
||||||
padding : 10px;
|
|
||||||
border-radius : 8px;
|
padding : 0 10px 10px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
font-size : 14px;
|
font-size : 14px;
|
||||||
font-family: "Poppins", sans-serif;
|
font-family: "Poppins", sans-serif;
|
||||||
@ -112,39 +157,38 @@
|
|||||||
|
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
|
|
||||||
#likes {
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
|
|
||||||
color: var(--primaryColor) !important;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
color : var(--background-color-contrast) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#likes:hover {
|
|
||||||
svg {
|
|
||||||
color: var(--primaryColor) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
cursor : pointer;
|
display : inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
cursor : pointer;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
|
position: absolute;
|
||||||
|
bottom : 0;
|
||||||
|
|
||||||
|
font-size : 14px;
|
||||||
|
font-family: "DM Mono", monospace;
|
||||||
|
|
||||||
|
transform : translate(0, 50%);
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
width : 0;
|
|
||||||
opacity : 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.action:hover {
|
.action:hover {
|
||||||
.value {
|
.icon {
|
||||||
margin-left: 3px;
|
svg {
|
||||||
width : 20px;
|
color: var(--primaryColor) !important;
|
||||||
opacity : 1;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,157 +234,4 @@
|
|||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@color-heart : #EA442B;
|
|
||||||
@likeAnimationDuration : .5s;
|
|
||||||
@likeAnimationEasing : cubic-bezier(.7, 0, .3, 1);
|
|
||||||
|
|
||||||
.likeButton {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
.ripple,
|
|
||||||
.ripple:before,
|
|
||||||
.ripple:after {
|
|
||||||
position : relative;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-size : 40px;
|
|
||||||
border : none;
|
|
||||||
border-radius: 50%;
|
|
||||||
width : 1em;
|
|
||||||
height : 1em;
|
|
||||||
padding : 0;
|
|
||||||
margin : 0;
|
|
||||||
outline : none;
|
|
||||||
z-index : 2;
|
|
||||||
transition : transform @likeAnimationDuration @likeAnimationEasing;
|
|
||||||
cursor : pointer;
|
|
||||||
|
|
||||||
background-color: transparent;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
z-index : -1;
|
|
||||||
content : '';
|
|
||||||
position : absolute;
|
|
||||||
top : 0;
|
|
||||||
left : 0;
|
|
||||||
width : 100%;
|
|
||||||
height : 100%;
|
|
||||||
border-radius: inherit;
|
|
||||||
transition : inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content : '';
|
|
||||||
position : absolute;
|
|
||||||
top : 0;
|
|
||||||
left : 0;
|
|
||||||
width : 100%;
|
|
||||||
height : 100%;
|
|
||||||
border-radius : inherit;
|
|
||||||
z-index : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heart {
|
|
||||||
position: relative;
|
|
||||||
>path {
|
|
||||||
stroke : var(--primaryColor);
|
|
||||||
stroke-width: 2;
|
|
||||||
transition : fill @likeAnimationDuration @likeAnimationEasing;
|
|
||||||
fill : var(--primaryColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.empty {
|
|
||||||
>path {
|
|
||||||
stroke : var(--primaryColor);
|
|
||||||
stroke-width: 2;
|
|
||||||
transition : fill @likeAnimationDuration @likeAnimationEasing;
|
|
||||||
fill : transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.clicked {
|
|
||||||
animation: heart-bounce @likeAnimationDuration @likeAnimationEasing;
|
|
||||||
|
|
||||||
@keyframes heart-bounce {
|
|
||||||
40% {
|
|
||||||
transform: scale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
0%,
|
|
||||||
80%,
|
|
||||||
100% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ripple {
|
|
||||||
position: absolute;
|
|
||||||
height : 1em;
|
|
||||||
width : 1em;
|
|
||||||
border-radius: 50%;
|
|
||||||
overflow : hidden;
|
|
||||||
z-index : 1;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content : '';
|
|
||||||
position : absolute;
|
|
||||||
top : 0;
|
|
||||||
left : 0;
|
|
||||||
width : 100%;
|
|
||||||
height : 100%;
|
|
||||||
border : .4em solid var(--primaryColor);
|
|
||||||
border-radius: inherit;
|
|
||||||
transform : scale(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.clicked {
|
|
||||||
&:before {
|
|
||||||
animation: ripple-out @likeAnimationDuration @likeAnimationEasing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes ripple-out {
|
|
||||||
from {
|
|
||||||
transform: scale(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
transform: scale(5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes depress {
|
|
||||||
|
|
||||||
from,
|
|
||||||
to {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
transform: translateY(5%) scale(0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes depress-shadow {
|
|
||||||
|
|
||||||
from,
|
|
||||||
to {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
transform: scale(0.5);
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user