mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Added in basic reply toggle with form ready for logic
This commit is contained in:
parent
8a67716b17
commit
70e435ccb3
4 changed files with 111 additions and 14 deletions
|
@ -6,14 +6,20 @@ import Reply from './Reply';
|
||||||
import More from './More';
|
import More from './More';
|
||||||
import EditForm from './EditForm';
|
import EditForm from './EditForm';
|
||||||
import Replies from './Replies';
|
import Replies from './Replies';
|
||||||
|
import ReplyForm from './ReplyForm';
|
||||||
|
|
||||||
const Comment = (props) => {
|
const Comment = (props) => {
|
||||||
const [isInEditMode, setIsInEditMode] = useState(false);
|
const [isInEditMode, setIsInEditMode] = useState(false);
|
||||||
|
const [isInReplyMode, setIsInReplyMode] = useState(false);
|
||||||
|
|
||||||
const toggleEditMode = () => {
|
const toggleEditMode = () => {
|
||||||
setIsInEditMode(current => !current);
|
setIsInEditMode(current => !current);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleReplyMode = () => {
|
||||||
|
setIsInReplyMode(current => !current);
|
||||||
|
};
|
||||||
|
|
||||||
const comment = props.comment;
|
const comment = props.comment;
|
||||||
const hasReplies = comment.replies && comment.replies.length > 0;
|
const hasReplies = comment.replies && comment.replies.length > 0;
|
||||||
const html = {__html: comment.html};
|
const html = {__html: comment.html};
|
||||||
|
@ -42,12 +48,17 @@ const Comment = (props) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-6">
|
<div className="flex gap-6">
|
||||||
<Like comment={comment} />
|
<Like comment={comment} />
|
||||||
<Reply comment={comment} />
|
{!props.isReply && <Reply comment={comment} toggleReply={toggleReplyMode} isReplying={isInReplyMode} />}
|
||||||
<More comment={comment} toggleEdit={toggleEditMode} />
|
<More comment={comment} toggleEdit={toggleEditMode} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{isInReplyMode &&
|
||||||
|
<div className={`ml-14 mt-8 ${!hasReplies ? 'mb-8' : ''}`}>
|
||||||
|
<ReplyForm />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
{hasReplies &&
|
{hasReplies &&
|
||||||
<div className="ml-14 mt-14">
|
<div className={`ml-14 ${isInReplyMode ? 'mt-8' : 'mt-14'}`}>
|
||||||
<Replies replies={comment.replies} />
|
<Replies replies={comment.replies} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,7 @@ import Comment from './Comment';
|
||||||
const Replies = (props) => {
|
const Replies = (props) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* {console.log(props.replies)} */}
|
{props.replies.map((reply => <Comment comment={reply} key={reply.id} isReply={true} />))}
|
||||||
{props.replies.map((reply => <Comment comment={reply} key={reply.id} />))}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
import React, {useState} from 'react';
|
import React from 'react';
|
||||||
import {ReactComponent as ReplyIcon} from '../images/icons/reply.svg';
|
import {ReactComponent as ReplyIcon} from '../images/icons/reply.svg';
|
||||||
|
|
||||||
function Reply() {
|
function Reply(props) {
|
||||||
const [replied, setReplied] = useState(false);
|
|
||||||
|
|
||||||
const toggleReply = () => {
|
|
||||||
setReplied(!replied);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className="flex font-sans items-center dark:text-white" onClick={toggleReply}>
|
<button className="flex font-sans items-center dark:text-white" onClick={props.toggleReply}>
|
||||||
<ReplyIcon className={`mr-[6px] stroke-dark dark:stroke-white ${replied ? 'fill-black dark:fill-white' : ''}`} />Reply
|
<ReplyIcon className={`mr-[6px] stroke-dark dark:stroke-white ${props.isReplying ? 'fill-black dark:fill-white' : ''}`} />Reply
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
93
apps/comments-ui/src/components/ReplyForm.js
Normal file
93
apps/comments-ui/src/components/ReplyForm.js
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import React from 'react';
|
||||||
|
import AppContext from '../AppContext';
|
||||||
|
import Avatar from './Avatar';
|
||||||
|
|
||||||
|
class ReplyForm extends React.Component {
|
||||||
|
static contextType = AppContext;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
message: '',
|
||||||
|
focused: false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.submitForm = this.submitForm.bind(this);
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.handleBlur = this.handleBlur.bind(this);
|
||||||
|
this.handleFocus = this.handleFocus.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getHTML() {
|
||||||
|
const text = this.state.message;
|
||||||
|
|
||||||
|
// Convert newlines to <br> for now (until we add a real editor)
|
||||||
|
return text.replace('\n', '<br>');
|
||||||
|
}
|
||||||
|
|
||||||
|
async submitForm(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// TODO: Add logic to make this work
|
||||||
|
|
||||||
|
// Clear message on success
|
||||||
|
this.setState({
|
||||||
|
message: '',
|
||||||
|
focused: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({message: event.target.value});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBlur(event) {
|
||||||
|
if (this.state.message === '') {
|
||||||
|
this.setState({focused: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFocus(event) {
|
||||||
|
this.setState({focused: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<form onSubmit={this.submitForm} className="comment-form">
|
||||||
|
<div className="w-full">
|
||||||
|
<div className="flex mb-4 space-x-4 justify-start items-center">
|
||||||
|
<Avatar />
|
||||||
|
<div>
|
||||||
|
<h4 className="text-lg font-sans font-bold mb-1 tracking-tight dark:text-neutral-300">{this.context.member.name}</h4>
|
||||||
|
<h6 className="text-[13px] text-neutral-400 font-sans">Now</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="pr-3 font-sans leading-normal dark:text-neutral-300">
|
||||||
|
<div className="relative w-full">
|
||||||
|
<textarea
|
||||||
|
className={`transition-[height] duration-150 w-full resize-none rounded-md border border-slate-200 p-3 font-sans mb-1 leading-normal focus:outline-0 dark:bg-[rgba(255,255,255,0.08)] dark:border-none dark:text-neutral-300 ${this.state.focused ? 'cursor-text h-40' : 'cursor-pointer overflow-hidden h-12 hover:border-slate-300'}`}
|
||||||
|
value={this.state.message}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
onFocus={this.handleFocus}
|
||||||
|
onBlur={this.handleBlur}
|
||||||
|
placeholder={this.state.focused ? '' : 'Reply to this comment'}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className={`transition-[opacity] duration-150 rounded-md border py-2 px-3 font-sans text-sm text-center bg-black font-semibold text-white dark:bg-[rgba(255,255,255,0.8)] dark:text-neutral-800 ${this.state.focused ? 'opacity-100' : 'opacity-0'}`}
|
||||||
|
type="submit">
|
||||||
|
Add your reply
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`transition-[opacity] duration-100 absolute top-2 right-2 rounded-md border py-1 px-2 font-sans text-sm text-center bg-black font-semibold text-white pointer-events-none dark:bg-[rgba(255,255,255,0.8)] dark:text-neutral-800 ${this.state.focused ? 'opacity-0' : 'opacity-100'}`}
|
||||||
|
disabled="true">
|
||||||
|
Reply
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReplyForm;
|
Loading…
Add table
Reference in a new issue