restyle PostCard

This commit is contained in:
SrGooglo 2023-02-24 14:33:00 +00:00
parent 5f03591d75
commit f3ccb4464f
13 changed files with 429 additions and 550 deletions

View File

@ -1,5 +1,5 @@
import React from "react" import React from "react"
import { Dropdown, Button } from "antd"
import { Icons } from "components/Icons" import { Icons } from "components/Icons"
import SaveButton from "./saveButton" import SaveButton from "./saveButton"
@ -7,28 +7,68 @@ import LikeButton from "./likeButton"
import "./index.less" import "./index.less"
const MoreActionsItems = [
{
key: "repost",
label: <>
<Icons.Repeat />
<span>Repost</span>
</>,
},
{
key: "share",
label: <>
<Icons.Share />
<span>Share</span>
</>,
},
{
type: "divider",
},
{
key: "report",
label: <>
<Icons.AlertTriangle />
<span>Report</span>
</>,
},
]
export default (props) => { export default (props) => {
return <div className="post_actionsWrapper"> return <div className="post_actions_wrapper">
<div className="actions"> <div className="actions">
<div className="action" id="likes"> <div className="action" id="likes">
<div className="icon"> <LikeButton
<LikeButton defaultLiked={props.defaultLiked} onClick={props.onClickLike} /> defaultLiked={props.defaultLiked}
</div> onClick={props.onClickLike}
count={props.likesCount}
/>
</div> </div>
<div className="action" id="save"> <div className="action" id="save">
<div className="icon"> <SaveButton
<SaveButton defaultActive={props.defaultSaved} onClick={props.onClickSave} /> defaultActive={props.defaultSaved}
</div> onClick={props.onClickSave}
/>
</div> </div>
<div className="action" id="share"> <div className="action" id="comments">
<div className="icon"> <Button
<Icons.Share2 onClick={props.onClickShare} /> type="ghost"
</div> shape="circle"
onClick={props.onClickComments}
icon={<Icons.MessageCircle />}
/>
</div> </div>
<div className="action" id="open" onClick={props.onClickOpen}> <div className="action" id="more">
<div className="icon"> <Dropdown
<Icons.MdOutlineOpenInNew className="icon" /> menu={{
</div> items: MoreActionsItems
}}
trigger={["click"]}
>
<div className="icon">
<Icons.MoreHorizontal />
</div>
</Dropdown>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,93 +1,47 @@
.post_actionsIndicator { .post_actions_wrapper {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: flex-start;
width: 10vw; position: relative;
padding: 2px;
margin: auto;
border-radius: 8px 8px 0 0;
background-color: var(--background-color-primary);
color: var(--background-color-contrast);
font-size: 18px;
transition: all 0.2s ease-in-out;
svg {
margin: 0 !important;
}
}
.post_actionsWrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
position: absolute;
bottom: 0;
left: 0;
opacity: 0;
width: 100%; width: 100%;
height: 40px; height: 40px;
margin-top: 15px; padding: 20px;
padding: 10px;
border-radius: 8px;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
background-color: var(--background-color-primary);
.actions { .actions {
display: inline-flex; display: inline-flex;
flex-direction: row; flex-direction: row;
align-items: center;
justify-content: space-between;
width: 80%;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
color: var(--background-color-contrast); width: 100%;
.action { .action {
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: row;
transition: all 0.2s ease-in-out; align-items: center;
justify-content: center;
.icon { transition: all 150ms ease-in-out;
cursor: pointer;
transition: all 0.2s ease-in-out;
svg { margin-right: 20px;
transition: all 0.2s ease-in-out;
}
&:last-child {
margin-right: 0;
} }
.value { &:hover {
position: absolute; .icon {
bottom: 0; svg {
color: var(--colorPrimary) !important;
font-size: 14px; }
font-family: "DM Mono", monospace;
transform: translate(0, 50%);
transition: all 0.2s ease-in-out;
}
}
.action:hover {
.icon {
svg {
color: var(--primaryColor) !important;
} }
} }
} }
@ -95,22 +49,5 @@
svg { svg {
margin: 0 !important; margin: 0 !important;
} }
>div {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border-radius: 360px;
width: 55px;
height: 55px;
font-size: 20px;
padding: 2px;
background-color: var(--background-color-primary);
transform: translate(0, -15px);
}
} }
} }

View File

@ -1,5 +1,6 @@
import React from "react" import React from "react"
import classnames from "classnames" import classnames from "classnames"
import CountUp from "react-countup"
import "./index.less" import "./index.less"
@ -22,27 +23,37 @@ export default (props) => {
setLiked(to) setLiked(to)
} }
return <button return <div
className={classnames("likeButton", { ["clicked"]: liked })} className={
classnames(
"like_btn_wrapper",
{
["liked"]: liked,
["clicked"]: clicked
}
)
}
onClick={handleClick} onClick={handleClick}
> >
<div <button className="like_btn">
className={classnames( <div className="ripple"></div>
"ripple", <svg
{ ["clicked"]: clicked } className="heart"
)} width="24"
></div> height="24"
<svg viewBox="0 0 24 24"
className={classnames( >
"heart", <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>
{ ["liked"]: liked }, </svg>
{ ["clicked"]: clicked }, </button>
)} <CountUp
width="24" start={props.count}
height="24" separator="."
viewBox="0 0 24 24" end={props.count}
> startOnMount={false}
<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> duration={3}
</svg> className="count"
</button> useEasing={true}
/>
</div>
} }

View File

@ -1,118 +1,161 @@
@color-heart : #EA442B; @color-heart : #EA442B;
@likeAnimationDuration : .5s; @likeAnimationDuration : .5s;
@likeAnimationEasing : cubic-bezier(.7, 0, .3, 1); @likeAnimationEasing : cubic-bezier(.7, 0, .3, 1);
.likeButton { .like_btn_wrapper {
display : flex; display: flex;
align-items : center; flex-direction: row;
justify-content: center; align-items: center;
.ripple, font-size: 1rem;
.ripple:before,
.ripple:after { .count {
position : relative; display: flex;
box-sizing: border-box; flex-direction: row;
align-items: center;
margin-left: 7px;
font-size: 0.8rem;
color: var(--text-color);
} }
font-size : 40px; //padding: 10px;
border : none; //border-radius: 8px;
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; transition: all @likeAnimationDuration @likeAnimationEasing;
&:before { &.liked {
z-index : -1; .like_btn {
content : ''; .heart {
position : absolute; >path {
top : 0; stroke: var(--colorPrimary);
left : 0; fill: var(--colorPrimary);
width : 100%; }
height : 100%;
border-radius: inherit;
transition : inherit;
}
&:after { filter: drop-shadow(0px 0px 2px var(--colorPrimary));
content : '';
position : absolute;
top : 0;
left : 0;
width : 100%;
height : 100%;
border-radius: inherit;
z-index : -1;
}
.heart {
position: relative;
>path {
stroke-width: 2;
transition : fill @likeAnimationDuration @likeAnimationEasing;
stroke : currentColor;
fill : transparent;
}
&.liked {
>path {
stroke: var(--primaryColor);
fill : var(--primaryColor);
} }
} }
&.clicked { //outline: 1px solid var(--colorPrimary);
animation: heart-bounce @likeAnimationDuration @likeAnimationEasing; }
@keyframes heart-bounce { &.clicked {
40% { .like_btn {
transform: scale(0.7); .heart {
animation: heart-bounce @likeAnimationDuration @likeAnimationEasing;
@keyframes heart-bounce {
40% {
transform: scale(0.7);
}
0%,
80%,
100% {
transform: scale(1);
}
} }
}
0%, .ripple {
80%, &:before {
100% { animation: ripple-out @likeAnimationDuration @likeAnimationEasing;
transform: scale(1);
} }
} }
} }
animation: none;
} }
.ripple { .like_btn {
position : absolute; display: flex;
height : 1em;
width : 1em; align-items: center;
justify-content: center;
.ripple,
.ripple:before,
.ripple:after {
position: relative;
box-sizing: border-box;
}
border: none;
border-radius: 50%; border-radius: 50%;
overflow : hidden;
z-index : 1; width: 1rem;
height: 1rem;
padding: 0;
margin: 0;
z-index: 2;
transition: transform @likeAnimationDuration @likeAnimationEasing;
background-color: transparent;
&:before { &:before {
content : ''; z-index: -1;
position : absolute; content: '';
top : 0; position: absolute;
left : 0; top: 0;
width : 100%; left: 0;
height : 100%; width: 1rem;
border : .4em solid var(--primaryColor); height: 1rem;
border-radius: inherit; border-radius: inherit;
transform : scale(0); transition: inherit;
} }
&.clicked { &:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 1rem;
height: 1rem;
border-radius: inherit;
z-index: -1;
}
.heart {
position: relative;
cursor: pointer;
>path {
stroke-width: 2;
transition: fill @likeAnimationDuration @likeAnimationEasing;
stroke: currentColor;
fill: transparent;
}
animation: none;
}
.ripple {
position: absolute;
height: 1rem;
width: 1rem;
border-radius: 50%;
overflow: hidden;
z-index: 1;
&:before { &:before {
animation: ripple-out @likeAnimationDuration @likeAnimationEasing; content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: .4em solid var(--colorPrimary);
border-radius: inherit;
transform: scale(0);
} }
} }
} }
} }

View File

@ -20,9 +20,9 @@ export default (props) => {
className={classnames("saveButton", { className={classnames("saveButton", {
["active"]: saved ["active"]: saved
})} })}
type="ghost"
shape="circle" shape="circle"
onClick={onClick} onClick={onClick}
icon={saved ? <Icons.MdBookmark /> : <Icons.MdBookmarkBorder />} icon={saved ? <Icons.MdBookmark /> : <Icons.MdBookmarkBorder />}
size="large"
/> />
} }

View File

@ -1,22 +1,21 @@
.saveButton { .saveButton {
border: 0 !important;
transition: all 150ms ease-in-out; transition: all 150ms ease-in-out;
background: transparent !important; background-color: transparent!important;
background-color: transparent !important; border: 0!important;
box-shadow: none!important;
&.active { &.active {
color: var(--primaryColor); color: var(--colorPrimary);
svg { svg {
color: var(--primaryColor); color: var(--colorPrimary);
} }
} }
svg { svg {
width: 20px; width: 1rem;
height: 20px; height: 1rem;
transition: all 150ms ease-in-out; transition: all 150ms ease-in-out;
} }

View File

@ -3,7 +3,6 @@ import { Skeleton } from "antd"
import { Carousel } from "react-responsive-carousel" import { Carousel } from "react-responsive-carousel"
import { ImageViewer } from "components" import { ImageViewer } from "components"
import Plyr from "plyr-react" import Plyr from "plyr-react"
import ModalImage from "react-modal-image"
import ContentFailed from "../contentFailed" import ContentFailed from "../contentFailed"
@ -43,7 +42,7 @@ const Attachment = React.memo((props) => {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
app.openFullImageViewer(url) app.controls.openFullImageViewer(url)
} }
} }

View File

@ -88,6 +88,12 @@
} }
.attachment { .attachment {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -136,7 +142,7 @@
.plyr__control { .plyr__control {
&:hover { &:hover {
background-color: var(--primaryColor); background-color: var(--colorPrimary);
} }
svg { svg {
@ -149,7 +155,7 @@
.plyr__progress, .plyr__progress,
.plyr__volume { .plyr__volume {
input { input {
color: var(--primaryColor); color: var(--colorPrimary);
} }
} }
} }

View File

@ -66,13 +66,13 @@
.message { .message {
width: 100%; width: 100%;
font-size: 14px; font-size: 0.9rem;
font-family: "Poppins", sans-serif; font-weight: 400;
color: var(--background-color-contrast);
word-break: break-all; word-break: break-all;
user-select: text; user-select: text;
color: var(--background-color-contrast)
} }
>div { >div {

View File

@ -1,5 +1,4 @@
import React from "react" import React from "react"
import classnames from "classnames"
import { DateTime } from "luxon" import { DateTime } from "luxon"
import { Image } from "components" import { Image } from "components"
@ -11,13 +10,13 @@ export default (props) => {
const [timeAgo, setTimeAgo] = React.useState(0) const [timeAgo, setTimeAgo] = React.useState(0)
const goToProfile = () => { const goToProfile = () => {
window.app.goToAccount(props.postData.user?.username) app.navigation.goToAccount(props.postData.user?.username)
} }
const updateTimeAgo = () => { const updateTimeAgo = () => {
let createdAt = props.postData.timestamp ?? props.postData.created_at ?? "" let createdAt = props.postData.timestamp ?? props.postData.created_at ?? ""
const timeAgo = DateTime.fromISO(createdAt).toRelative() const timeAgo = DateTime.fromISO(createdAt, { locale: app.cores.settings.get("language") }).toRelative()
setTimeAgo(timeAgo) setTimeAgo(timeAgo)
} }
@ -43,30 +42,14 @@ export default (props) => {
/> />
</div> </div>
<div className="info"> <div className="info">
<div> <h1 onClick={goToProfile}>
<h1 onClick={goToProfile}> {props.postData.user?.fullName ?? `@${props.postData.user?.username}`}
{props.postData.user?.fullName ?? `@${props.postData.user?.username}`} {props.postData.user?.verified && <Icons.verifiedBadge />}
{props.postData.user?.verified && <Icons.verifiedBadge />} </h1>
</h1>
</div>
<div> <span className="timeago">
{timeAgo} {timeAgo}
</div> </span>
</div>
</div>
<div className="statistics">
<div className="item">
<Icons.Heart className={classnames("icon", { ["filled"]: props.isLiked })} />
<div className="value">
{props.likes}
</div>
</div>
<div className="item">
<Icons.MessageSquare />
<div className="value">
{props.comments}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -15,7 +15,7 @@
} }
svg { svg {
fill: var(--appColor); fill: var(--app-color);
margin-left: 6px; margin-left: 6px;
} }
@ -35,22 +35,29 @@
.info { .info {
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: column;
align-items: center;
justify-content: start;
text-align: start; align-items: flex-start;
width: fit-content; width: fit-content;
color: var(--background-color-contrast);
h1 { h1 {
color: var(--background-color-contrast); margin: 0 0 4px 0;
margin: 0;
font-family: "DM Mono", monospace;
align-self: start; align-self: start;
font-weight: 500;
font-size: 1rem; font-size: 1rem;
cursor: pointer; cursor: pointer;
color: var(--background-color-contrast);
}
.timeago {
font-weight: 400;
font-size: 0.7rem;
color: rgb(var(--bg_color_4));
} }
>div { >div {
@ -58,35 +65,4 @@
} }
} }
} }
.statistics {
display: inline-flex;
flex-direction: column;
font-size: 16px;
color: var(--background-color-contrast);
height: fit-content;
.item {
display: inline-flex;
align-items: center;
justify-content: flex-end;
height: fit-content;
margin-left: 20px;
margin-bottom: 5px;
.icon {
&.filled {
color: var(--primaryColor);
fill: var(--primaryColor);
}
}
.value {
font-family: "DM Mono", monospace;
font-size: 14px;
}
}
}
} }

View File

@ -2,6 +2,7 @@ import React from "react"
import * as antd from "antd" import * as antd from "antd"
import classnames from "classnames" import classnames from "classnames"
import { CommentsCard } from "components"
import { Icons } from "components/Icons" import { Icons } from "components/Icons"
import PostHeader from "./components/header" import PostHeader from "./components/header"
@ -11,184 +12,116 @@ import PostAttachments from "./components/attachments"
import "./index.less" import "./index.less"
export default ({ export default class PostCard extends React.Component {
expansibleActions = window.app.settings.get("postCard_expansible_actions"), state = {
autoCarrousel = window.app.settings.get("postCard_carrusel_auto"), loading: true,
data = {}, data: this.props.data ?? {},
events = {},
fullmode
}) => {
const isSelf = app.permissions.checkUserIdIsSelf(data.user_id)
const [loading, setLoading] = React.useState(true) countLikes: this.props.data.countLikes ?? 0,
countComments: this.props.data.countComments ?? 0,
const [likes, setLikes] = React.useState(data.likes ?? []) hasLiked: this.props.data.isLiked ?? false,
const [comments, setComments] = React.useState(data.comments ?? []) hasSaved: this.props.data.isSaved ?? false,
const [hasLiked, setHasLiked] = React.useState(false) open: this.props.defaultOpened ?? false,
const [hasSaved, setHasSaved] = React.useState(false) }
const onClickDelete = async () => { onClickDelete = async () => {
if (typeof events.onClickDelete !== "function") { if (typeof this.props.events.onClickDelete !== "function") {
console.warn("onClickDelete event is not a function") console.warn("onClickDelete event is not a function")
return return
} }
return await events.onClickDelete(data) return await this.props.events.onClickDelete(this.state.data)
} }
const onClickLike = async () => { onClickLike = async () => {
if (typeof events.onClickLike !== "function") { if (typeof this.props.events.onClickLike !== "function") {
console.warn("onClickLike event is not a function") console.warn("onClickLike event is not a function")
return return
} }
return await events.onClickLike(data) return await this.props.events.onClickLike(this.state.data)
} }
const onClickSave = async () => { onClickSave = async () => {
if (typeof events.onClickSave !== "function") { if (typeof this.props.events.onClickSave !== "function") {
console.warn("onClickSave event is not a function") console.warn("onClickSave event is not a function")
return return
} }
return await events.onClickSave(data) return await this.props.events.onClickSave(this.state.data)
} }
const onClickOpen = async () => { onClickEdit = async () => {
if (typeof events.onClickOpen !== "function") { if (typeof this.props.events.onClickEdit !== "function") {
console.warn("onClickOpen event is not a function, performing default action")
return window.app.goToPost(data._id)
}
return await events.onClickOpen(data)
}
const onClickEdit = async () => {
if (typeof events.onClickEdit !== "function") {
console.warn("onClickEdit event is not a function") console.warn("onClickEdit event is not a function")
return return
} }
return await events.onClickEdit(data) return await this.props.events.onClickEdit(this.state.data)
} }
const onDataUpdate = (data) => { onDoubleClick = async () => {
console.log("onDataUpdate", data) this.handleOpen()
setLikes(data.likes)
setComments(data.comments)
} }
const onDoubleClick = () => { onClickComments = async () => {
if (typeof events.onDoubleClick !== "function") { this.handleOpen()
console.warn("onDoubleClick event is not a function") }
return
handleOpen = (to) => {
if (typeof to === "undefined") {
to = !this.state.open
} }
return events.onDoubleClick(data) if (typeof this.props.events?.onToogleOpen === "function") {
} this.props.events?.onToogleOpen(to, this.state.data)
React.useEffect(() => {
if (fullmode) {
app.eventBus.emit("style.compactMode", true)
} }
app.eventBus.on(`post.${data._id}.delete`, onClickDelete) this.setState({
app.eventBus.on(`post.${data._id}.update`, onClickEdit) open: to,
})
//app.controls.openPostViewer(this.state.data)
}
onLikesUpdate = (data) => {
if (data.to) {
this.setState({
countLikes: this.state.countLikes + 1,
})
} else {
this.setState({
countLikes: this.state.countLikes - 1,
})
}
}
componentDidMount = async () => {
app.eventBus.on(`post.${this.state.data._id}.delete`, this.onClickDelete)
app.eventBus.on(`post.${this.state.data._id}.update`, this.onClickEdit)
// first listen to post changes // first listen to post changes
window.app.api.namespaces["main"].listenEvent(`post.dataUpdate.${data._id}`, onDataUpdate) //window.app.cores.api.namespaces["main"].listenEvent(`post.dataUpdate.${data._id}`, onDataUpdate)
window.app.cores.api.namespaces["main"].listenEvent(`post.${this.state.data._id}.likes.update`, this.onLikesUpdate)
// then load this.setState({
setLoading(false) isSelf: app.cores.permissions.checkUserIdIsSelf(this.state.data.user_id),
loading: false,
return () => { })
if (fullmode) {
app.eventBus.emit("style.compactMode", false)
}
app.eventBus.off(`post.${data._id}.delete`, onClickDelete)
app.eventBus.off(`post.${data._id}.update`, onClickEdit)
// remove the listener
window.app.api.namespaces["main"].unlistenEvent(`post.dataUpdate.${data._id}`, onDataUpdate)
}
}, [])
React.useEffect(() => {
if (!app.userData) {
return
}
// check if the post has liked by you
const hasLiked = likes.includes(app.userData._id)
const hasSaved = data.isSaved
setHasLiked(hasLiked)
setHasSaved(hasSaved)
})
if (loading) {
return <antd.Skeleton active />
} }
try { componentWillUnmount = () => {
return <div app.eventBus.off(`post.${this.state.data._id}.delete`, this.onClickDelete)
key={data.key ?? data._id} app.eventBus.off(`post.${this.state.data._id}.update`, this.onClickEdit)
id={data._id}
className={classnames( // remove the listener
"postCard", //window.app.cores.api.namespaces["main"].unlistenEvent(`post.dataUpdate.${data._id}`, onDataUpdate)
data.type, window.app.cores.api.namespaces["main"].listenEvent(`post.${this.state.data._id}.likes.update`, this.onLikesUpdate)
{ ["liked"]: hasLiked }, }
{ ["noHide"]: window.isMobile || !expansibleActions },
{ ["fullmode"]: fullmode }, componentDidCatch = (error, info) => {
)}
context-menu={"postCard-context"}
user-id={data.user_id}
self-post={isSelf.toString()}
>
<div className="wrapper">
<PostHeader
postData={data}
isLiked={hasLiked}
likes={likes.length}
comments={comments.length}
fullmode={fullmode}
onDoubleClick={onDoubleClick}
/>
<PostContent
data={data}
autoCarrousel={autoCarrousel}
fullmode={fullmode}
onDoubleClick={onDoubleClick}
nsfw={data.flags && data.flags.includes("nsfw")}
>
{data.attachments && data.attachments.length > 0 && <PostAttachments
attachments={data.attachments}
/>}
</PostContent>
</div>
{!fullmode &&
<div className="post_actionsIndicator">
<Icons.MoreHorizontal />
</div>
}
{!fullmode &&
<PostActions
defaultLiked={hasLiked}
defaultSaved={hasSaved}
onClickLike={onClickLike}
onClickSave={onClickSave}
onClickOpen={onClickOpen}
actions={{
delete: onClickDelete,
}}
fullmode={fullmode}
/>
}
</div>
} catch (error) {
console.error(error) console.error(error)
return <div className="postCard error"> return <div className="postCard error">
@ -201,4 +134,63 @@ export default ({
</h1> </h1>
</div> </div>
} }
render = () => {
if (this.state.loading) {
return <div
key={this.state.data.key ?? this.state.data._id}
id={this.state.data._id}
className="postCard"
>
<antd.Skeleton active avatar />
</div>
}
return <div
key={this.state.data.key ?? this.state.data._id}
id={this.state.data._id}
className={classnames(
"postCard",
{
["open"]: this.state.open,
}
)}
context-menu={"postCard-context"}
user-id={this.state.data.user_id}
self-post={this.state.isSelf.toString()}
>
<div className="wrapper">
<PostHeader
postData={this.state.data}
isLiked={this.state.hasLiked}
onDoubleClick={this.onDoubleClick}
/>
<PostContent
data={this.state.data}
nsfw={this.state.data.flags && this.state.data.flags.includes("nsfw")}
onDoubleClick={this.onDoubleClick}
>
{this.state.data.attachments && this.state.data.attachments.length > 0 && <PostAttachments
attachments={this.state.data.attachments}
/>}
</PostContent>
</div>
<PostActions
likesCount={this.state.countLikes}
commentsCount={this.state.countComments}
defaultLiked={this.state.hasLiked}
defaultSaved={this.state.hasSaved}
onClickLike={this.onClickLike}
onClickSave={this.onClickSave}
onClickComments={this.onClickComments}
actions={{
delete: this.onClickDelete,
}}
/>
{
this.state.open && <CommentsCard post_id={this.state.data._id} />
}
</div>
}
} }

View File

@ -5,127 +5,14 @@
width: 100%; width: 100%;
max-width: 600px; max-width: 600px;
filter: drop-shadow(3px 3px 2px var(--shadow-color));
background-color: var(--background-color-accent); background-color: var(--background-color-accent);
border-radius: 8px;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
outline-width: 1px; padding: 17px;
outline-style: solid;
outline-color: transparent;
&.playlist { &.open {
.wrapper {
.post_content {
flex-direction: row;
background-color: var(--background-color-primary);
padding: 20px;
.playlistCover {
width: 200px;
height: 200px;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
border-radius: 8px;
margin-right: 25px;
}
.playlistTitle {
h1 {
font-size: 1.5rem;
font-family: "Space Grotesk", sans-serif;
margin: 0;
}
h3 {
font-size: 0.9rem;
// make italic
font-style: italic;
}
.actions {
width: 100%;
margin-top: 20px;
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
}
}
}
}
&.liked {
filter: drop-shadow(0px 0px 2px var(--primaryColor));
outline-color: var(--primaryColor);
}
&.noHide {
.wrapper {
margin-bottom: 25px;
}
.post_actionsWrapper {
opacity: 1;
}
}
&.fullmode {
max-width: none;
height: 100%; height: 100%;
background-color: transparent;
filter: none!important;
outline: none!important;
.post_actionsIndicator {
opacity: 0;
}
.post_actionsWrapper {
opacity: 1;
}
.wrapper {
height: 100%;
.post_content {
height: 100%;
.post_attachments {
.carousel-root {
.carousel {
height: 100%;
min-height: 70vh;
.addition {
height: 100%;
min-height: 70vh;
.plyr {
height: 100%;
}
img,
video {
height: 100%;
object-fit: contain;
}
}
}
}
}
}
}
} }
.wrapper { .wrapper {
@ -134,7 +21,6 @@
align-items: center; align-items: center;
width: 100%; width: 100%;
padding: 17px;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
@ -143,13 +29,20 @@
} }
} }
&:hover { border-bottom: 2px solid var(--border-color);
.wrapper {
margin-bottom: 25px;
}
.post_actionsWrapper { padding-bottom: 10px;
opacity: 1;
} &:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
&:last-child {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom: none;
padding-bottom: 0;
} }
} }