mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-22 19:32:54 +03:00
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:
parent
3e6b3bda8a
commit
403cac4c42
@ -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>
|
||||
|
@ -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>} */}
|
||||
|
@ -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>
|
||||
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user