Focused reply box when clicking comment button on feed item

ref https://linear.app/tryghost/issue/AP-396

I think it's nicer API to pass in a focused property, rather than an
element ref, but I don't have much experience here, so it might be the
wrong approach!
This commit is contained in:
Fabien O'Carroll 2024-09-19 13:07:51 +07:00 committed by Fabien 'egg' O'Carroll
parent 3e6b3bda8a
commit 403cac4c42
4 changed files with 30 additions and 14 deletions

View File

@ -44,10 +44,10 @@ const Inbox: React.FC<InboxProps> = ({}) => {
return commentsMap.get(id) ?? [];
};
const handleViewContent = (object: ObjectProperties, actor: ActorProperties, comments: Activity[]) => {
const handleViewContent = (object: ObjectProperties, actor: ActorProperties, comments: Activity[], focusReply = false) => {
setArticleContent(object);
setArticleActor(actor);
NiceModal.show(ArticleModal, {object, actor, comments, allComments: commentsMap});
NiceModal.show(ArticleModal, {object, actor, comments, allComments: commentsMap, focusReply});
};
function getContentAuthor(activity: Activity) {
@ -101,6 +101,12 @@ const Inbox: React.FC<InboxProps> = ({}) => {
layout={layout}
object={activity.object}
type={activity.type}
onCommentClick={() => handleViewContent(
activity.object,
getContentAuthor(activity),
getCommentsForObject(activity.object.id),
true
)}
/>
{index < activities.length - 1 && (
<div className="h-px w-full bg-grey-200"></div>

View File

@ -17,6 +17,7 @@ interface ArticleModalProps {
actor: ActorProperties;
comments: Activity[];
allComments: Map<string, Activity[]>;
focusReply: boolean;
}
const ArticleBody: React.FC<{heading: string, image: string|undefined, html: string}> = ({heading, image, html}) => {
@ -74,7 +75,7 @@ const FeedItemDivider: React.FC = () => (
<div className="mx-[-32px] h-px w-[120%] bg-grey-200"></div>
);
const ArticleModal: React.FC<ArticleModalProps> = ({object, actor, comments, allComments}) => {
const ArticleModal: React.FC<ArticleModalProps> = ({object, actor, comments, allComments, focusReply}) => {
const MODAL_SIZE_SM = 640;
const MODAL_SIZE_LG = 2800;
@ -152,7 +153,7 @@ const ArticleModal: React.FC<ArticleModalProps> = ({object, actor, comments, all
object={object}
type='Note'
/>
<APReplyBox object={object}/>
<APReplyBox focused={focusReply} object={object}/>
<FeedItemDivider />
{/* {object.content && <div dangerouslySetInnerHTML={({__html: object.content})} className='ap-note-content text-pretty text-[1.5rem] text-grey-900'></div>} */}

View File

@ -205,11 +205,12 @@ interface FeedItemProps {
comments?: Activity[];
last?: boolean;
onClick?: () => void;
onCommentClick?: () => void;
}
const noop = () => {};
const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comments = [], last, onClick = noop}) => {
const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comments = [], last, onClick = noop, onCommentClick}) => {
const timestamp =
new Date(object?.published ?? new Date()).toLocaleDateString('default', {year: 'numeric', month: 'short', day: '2-digit'}) + ', ' + new Date(object?.published ?? new Date()).toLocaleTimeString('default', {hour: '2-digit', minute: '2-digit'});
@ -292,7 +293,7 @@ const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comment
</div>
</div>
<Menu items={menuItems} position='end' trigger={UserMenuTrigger}/>
</div>
<div className={`relative z-10 col-start-2 col-end-3 w-full gap-4`}>
<div className='flex flex-col'>
@ -303,7 +304,7 @@ const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comment
commentCount={comments.length}
likeCount={1}
object={object}
onCommentClick={onLikeClick}
onCommentClick={onCommentClick}
onLikeClick={onLikeClick}
/>
</div>
@ -348,7 +349,7 @@ const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comment
commentCount={comments.length}
likeCount={1}
object={object}
onCommentClick={onLikeClick}
onCommentClick={onCommentClick}
onLikeClick={onLikeClick}
/>
</div>
@ -395,7 +396,7 @@ const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comment
commentCount={comments.length}
likeCount={1}
object={object}
onCommentClick={onLikeClick}
onCommentClick={onCommentClick}
onLikeClick={onLikeClick}
/>
</div>
@ -432,7 +433,7 @@ const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comment
commentCount={comments.length}
likeCount={1}
object={object}
onCommentClick={onLikeClick}
onCommentClick={onCommentClick}
onLikeClick={onLikeClick}
/>
</div>

View File

@ -1,4 +1,4 @@
import React, {HTMLProps, useId, useState} from 'react';
import React, {HTMLProps, useEffect, useId, useRef, useState} from 'react';
import * as FormPrimitive from '@radix-ui/react-form';
import APAvatar from './APAvatar';
@ -10,7 +10,6 @@ import {useReplyMutationForUser, useUserDataForUser} from '../../hooks/useActivi
// import {useFocusContext} from '@tryghost/admin-x-design-system/types/providers/DesignSystemProvider';
export interface APTextAreaProps extends HTMLProps<HTMLTextAreaElement> {
inputRef?: React.RefObject<HTMLTextAreaElement>;
title?: string;
value?: string;
rows?: number;
@ -20,10 +19,10 @@ export interface APTextAreaProps extends HTMLProps<HTMLTextAreaElement> {
className?: string;
onChange?: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
object: ObjectProperties;
focused: boolean;
}
const APReplyBox: React.FC<APTextAreaProps> = ({
inputRef,
title,
value,
rows = 1,
@ -32,6 +31,7 @@ const APReplyBox: React.FC<APTextAreaProps> = ({
hint,
className,
object,
focused,
// onChange,
// onFocus,
// onBlur,
@ -43,6 +43,14 @@ const APReplyBox: React.FC<APTextAreaProps> = ({
const {data: user} = useUserDataForUser('index');
const textareaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
if (textareaRef.current && focused) {
textareaRef.current.focus();
}
}, [focused]);
const styles = clsx(
'ap-textarea order-2 w-full resize-none rounded-lg border py-2 pr-3 text-[1.5rem] transition-all dark:text-white',
error ? 'border-red' : 'border-transparent placeholder:text-grey-500 dark:placeholder:text-grey-800',
@ -76,7 +84,7 @@ const APReplyBox: React.FC<APTextAreaProps> = ({
<FormPrimitive.Field name={id} asChild>
<FormPrimitive.Control asChild>
<textarea
ref={inputRef}
ref={textareaRef}
className={styles}
id={id}
maxLength={maxLength}