mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
commit
c6953bdc6a
@ -12,6 +12,7 @@
|
||||
"variants": {
|
||||
"light": {
|
||||
"appColor": "#ff6064",
|
||||
"text-color": "#000000",
|
||||
"layoutBackgroundColor": "255, 255, 255",
|
||||
"background-color-primary": "#ffffff",
|
||||
"background-color-primary2": "#f0f0f0",
|
||||
|
13
packages/app/src/components/CommentCreator/index.jsx
Normal file
13
packages/app/src/components/CommentCreator/index.jsx
Normal file
@ -0,0 +1,13 @@
|
||||
import React from "react"
|
||||
import * as antd from "antd"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
export default (props) => {
|
||||
return <div className="commentCreator">
|
||||
<antd.Input.TextArea
|
||||
placeholder="Write a comment..."
|
||||
autoSize={{ minRows: 2, maxRows: 5 }}
|
||||
/>
|
||||
</div>
|
||||
}
|
22
packages/app/src/components/CommentCreator/index.less
Normal file
22
packages/app/src/components/CommentCreator/index.less
Normal file
@ -0,0 +1,22 @@
|
||||
.commentCreator {
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
align-items: right;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.ant-input {
|
||||
background-color: var(--background-color-accent) !important;
|
||||
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.ant-btn {
|
||||
width: fit-content;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
86
packages/app/src/components/CommentsCard/index.jsx
Normal file
86
packages/app/src/components/CommentsCard/index.jsx
Normal file
@ -0,0 +1,86 @@
|
||||
import React from "react"
|
||||
import * as antd from "antd"
|
||||
import moment from "moment"
|
||||
|
||||
import { CommentCreator } from "components"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
export default (props) => {
|
||||
const [postData, setPostData] = React.useState(null)
|
||||
const [comments, setComments] = React.useState(null)
|
||||
|
||||
const fetchData = async () => {
|
||||
setPostData(null)
|
||||
setComments(null)
|
||||
|
||||
// fetch post data
|
||||
const postDataResult = await window.app.api.request("main", "get", `post`, undefined, {
|
||||
post_id: props.post_id
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
|
||||
antd.message.error("Failed to fetch post data")
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
if (!postDataResult) return
|
||||
|
||||
setPostData(postDataResult)
|
||||
|
||||
// fetch comments
|
||||
const commentsResult = await window.app.api.customRequest("main", {
|
||||
method: "get",
|
||||
url: `/post/${props.post_id}/comments`,
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
|
||||
antd.message.error("Failed to fetch comments")
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
console.log(commentsResult)
|
||||
|
||||
if (!commentsResult) return
|
||||
|
||||
setComments(commentsResult.data)
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchData()
|
||||
}, [])
|
||||
|
||||
const renderComments = () => {
|
||||
return comments.map((comment) => {
|
||||
return <div className="comment" id={comment._id}>
|
||||
<div className="header">
|
||||
<div className="avatar">
|
||||
<antd.Avatar src={comment.user.avatar} />
|
||||
</div>
|
||||
<div className="username">
|
||||
{comment.user.username}
|
||||
</div>
|
||||
<div className="timeAgo">
|
||||
{moment(comment.createdAt).fromNow()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="content">
|
||||
{comment.message}
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
|
||||
if (!comments) {
|
||||
return <antd.Skeleton active />
|
||||
}
|
||||
|
||||
return <div className="comments">
|
||||
{renderComments()}
|
||||
<div className="commentCreatorWrapper">
|
||||
<CommentCreator />
|
||||
</div>
|
||||
</div>
|
||||
}
|
71
packages/app/src/components/CommentsCard/index.less
Normal file
71
packages/app/src/components/CommentsCard/index.less
Normal file
@ -0,0 +1,71 @@
|
||||
.comments {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
padding: 10px;
|
||||
|
||||
.comment {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
margin-bottom: 10px;
|
||||
|
||||
background-color: var(--background-color-accent);
|
||||
|
||||
padding: 10px;
|
||||
|
||||
border-radius: 8px;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
margin-bottom: 15px;
|
||||
|
||||
.avatar {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.timeAgo {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 14px;
|
||||
color: var(--text-color);
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.commentCreatorWrapper {
|
||||
position: sticky;
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
|
||||
width: 100%;
|
||||
padding: 30px 5px;
|
||||
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 10px;
|
||||
|
||||
background-color: rgba(var(--background-color-accent), 0.6);
|
||||
}
|
||||
}
|
@ -349,6 +349,16 @@ export const PostCard = React.memo(({
|
||||
return events.onDoubleClick(data)
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (fullmode) {
|
||||
app.eventBus.emit("style.compactMode", true)
|
||||
}
|
||||
|
||||
return () => {
|
||||
app.eventBus.emit("style.compactMode", false)
|
||||
}
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
// first listen to post changes
|
||||
window.app.api.namespaces["main"].listenEvent(`post.dataUpdate.${data._id}`, onDataUpdate)
|
||||
@ -397,29 +407,36 @@ export const PostCard = React.memo(({
|
||||
isLiked={hasLiked}
|
||||
likes={likes.length}
|
||||
comments={comments.length}
|
||||
fullmode={fullmode}
|
||||
/>
|
||||
<PostContent
|
||||
data={data}
|
||||
autoCarrousel={autoCarrousel}
|
||||
fullmode={fullmode}
|
||||
/>
|
||||
</div>
|
||||
<div className="actionsIndicatorWrapper">
|
||||
<div className="actionsIndicator">
|
||||
<Icons.MoreHorizontal />
|
||||
{!fullmode &&
|
||||
<div className="actionsIndicatorWrapper">
|
||||
<div className="actionsIndicator">
|
||||
<Icons.MoreHorizontal />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="actionsWrapper">
|
||||
<PostActions
|
||||
isSelf={selfId === data.user_id}
|
||||
defaultLiked={hasLiked}
|
||||
defaultSaved={hasSaved}
|
||||
onClickLike={onClickLike}
|
||||
onClickSave={onClickSave}
|
||||
actions={{
|
||||
delete: onClickDelete,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{!fullmode &&
|
||||
<div className="actionsWrapper">
|
||||
<PostActions
|
||||
isSelf={selfId === data.user_id}
|
||||
defaultLiked={hasLiked}
|
||||
defaultSaved={hasSaved}
|
||||
onClickLike={onClickLike}
|
||||
onClickSave={onClickSave}
|
||||
actions={{
|
||||
delete: onClickDelete,
|
||||
}}
|
||||
fullmode={fullmode}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
})
|
||||
|
||||
|
@ -33,6 +33,51 @@
|
||||
|
||||
&.fullmode {
|
||||
max-width: none;
|
||||
height: 100%;
|
||||
|
||||
background-color: transparent;
|
||||
|
||||
filter: none;
|
||||
|
||||
.actionsIndicatorWrapper {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.actionsWrapper {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
height: 100%;
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
|
||||
.additions {
|
||||
height: fit-content;
|
||||
max-height: 80vh;
|
||||
|
||||
.addition {
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
img,
|
||||
video {
|
||||
width: fit-content;
|
||||
height: 100%;
|
||||
|
||||
align-self: center;
|
||||
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
|
@ -40,6 +40,10 @@ export { default as PostsFeed } from "./PostsFeed"
|
||||
export { default as PostCard } from "./PostCard"
|
||||
export { default as PostCreator } from "./PostCreator"
|
||||
|
||||
// COMMENTS
|
||||
export { default as CommentsCard } from "./CommentsCard"
|
||||
export { default as CommentCreator } from "./CommentCreator"
|
||||
|
||||
// USERS
|
||||
export { default as FollowersList } from "./FollowersList"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react"
|
||||
import * as antd from "antd"
|
||||
|
||||
import { PostCard } from "components"
|
||||
import { PostCard, CommentsCard } from "components"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
@ -28,6 +28,11 @@ export default (props) => {
|
||||
}
|
||||
|
||||
return <div className="fullPost">
|
||||
<PostCard data={data} fullmode />
|
||||
<div className="postWrapper">
|
||||
<PostCard data={data} fullmode />
|
||||
</div>
|
||||
<div className="commentsWrapper">
|
||||
<CommentsCard post_id={data._id} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
@ -1,3 +1,28 @@
|
||||
.fullPost {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
.postWrapper {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.commentsWrapper {
|
||||
max-width: 600px;
|
||||
min-width: 400px;
|
||||
|
||||
width: 40%;
|
||||
height: 100vh;
|
||||
|
||||
overflow: scroll;
|
||||
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ export default class Server {
|
||||
controllers.PostsController,
|
||||
controllers.StreamingController,
|
||||
controllers.BadgesController,
|
||||
controllers.CommentsController,
|
||||
]
|
||||
|
||||
middlewares = middlewares
|
||||
|
@ -2,15 +2,70 @@ import { Controller } from "linebridge/dist/server"
|
||||
import { User, Post, Comment } from "../../models"
|
||||
import { Schematized } from "../../lib"
|
||||
|
||||
import getComments from "./methods/getComments"
|
||||
|
||||
export default class CommentsController extends Controller {
|
||||
static refName = "CommentsController"
|
||||
|
||||
get = {
|
||||
|
||||
"/comments": {
|
||||
fn: Schematized({
|
||||
required: ["targetId"],
|
||||
select: ["targetId"],
|
||||
}, async (req, res) => {
|
||||
|
||||
})
|
||||
},
|
||||
"/post/:post_id/comments": {
|
||||
fn: async (req, res) => {
|
||||
const { post_id } = req.params
|
||||
|
||||
let comments = await Comment.find({ parent_id: post_id }).catch(err => {
|
||||
res.status(500).json({ message: err.message })
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
if (comments) {
|
||||
// fullfill comments with user data
|
||||
comments = await Promise.all(comments.map(async comment => {
|
||||
const user = await User.findById(comment.user_id)
|
||||
|
||||
return {
|
||||
...comment.toObject(),
|
||||
user: user.toObject(),
|
||||
}
|
||||
}))
|
||||
|
||||
return res.json(comments)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post = {
|
||||
|
||||
"/post/:post_id/comment": {
|
||||
middlewares: ["withAuthentication"],
|
||||
fn: Schematized({
|
||||
required: ["message"],
|
||||
select: ["message"],
|
||||
}, async (req, res) => {
|
||||
const { post_id } = req.params
|
||||
const { message } = req.selection
|
||||
|
||||
const comment = new Comment({
|
||||
user_id: req.user._id.toString(),
|
||||
parent_id: post_id,
|
||||
message: message,
|
||||
})
|
||||
|
||||
await comment.save()
|
||||
|
||||
if (comment) {
|
||||
return res.json(comment)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
put = {
|
||||
|
@ -0,0 +1,11 @@
|
||||
import { User, Post, Comment } from "../../../models"
|
||||
|
||||
export default (payload) => {
|
||||
const { parent_id, _id } = payload
|
||||
|
||||
if (typeof _id !== "undefined") {
|
||||
return Comment.findById(_id)
|
||||
}
|
||||
|
||||
return Comment.find({ parent_id })
|
||||
}
|
@ -6,4 +6,5 @@ export { default as FilesController } from "./FilesController"
|
||||
export { default as PublicController } from "./PublicController"
|
||||
export { default as PostsController } from "./PostsController"
|
||||
export { default as StreamingController } from "./StreamingController"
|
||||
export { default as BadgesController } from "./BadgesController"
|
||||
export { default as BadgesController } from "./BadgesController"
|
||||
export { default as CommentsController } from "./CommentsController"
|
@ -1,7 +1,7 @@
|
||||
export default {
|
||||
user_id: { type: String, required: true },
|
||||
parent_id: { type: String, required: true },
|
||||
content: { type: String, required: true },
|
||||
message: { type: String, required: true },
|
||||
created_at: { type: Date, default: Date.now },
|
||||
liked: { type: Array, default: [] },
|
||||
//liked: { type: Array, default: [] },
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user