Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 96 additions & 28 deletions packages/editor/src/components/collab-sidebar/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { focusCommentThread, getCommentExcerpt } from './utils';
import { useFloatingThread } from './hooks';
import { AddComment } from './add-comment';
import { store as editorStore } from '../../store';
import MinifiedThreadIndicator from './minified-thread-indicator';

const { useBlockElement } = unlock( blockEditorPrivateApis );
const { Menu } = unlock( componentsPrivateApis );
Expand All @@ -59,6 +60,7 @@ export function Comments( {
reflowComments,
isFloating = false,
commentLastUpdated,
isCompactNotes = false,
} ) {
const [ heights, setHeights ] = useState( {} );
const [ selectedThread, setSelectedThread ] = useState( null );
Expand Down Expand Up @@ -404,38 +406,104 @@ export function Comments( {
commentSidebarRef={ commentSidebarRef }
/>
) }
{ threads.map( ( thread ) => (
<Thread
key={ thread.id }
thread={ thread }
onAddReply={ onAddReply }
onCommentDelete={ handleDelete }
onEditComment={ onEditComment }
isSelected={ selectedThread === thread.id }
setSelectedThread={ setSelectedThread }
setNewNoteFormState={ setNewNoteFormState }
commentSidebarRef={ commentSidebarRef }
reflowComments={ reflowComments }
isFloating={ isFloating }
calculatedOffset={ boardOffsets[ thread.id ] ?? 0 }
setHeights={ setHeights }
setBlockRef={ setBlockRef }
selectedThread={ selectedThread }
commentLastUpdated={ commentLastUpdated }
newNoteFormState={ newNoteFormState }
onKeyDown={ ( event ) =>
handleThreadNavigation(
event,
thread,
selectedThread === thread.id
)
}
/>
) ) }
{ threads.map( ( thread ) => {
const isSelected = selectedThread === thread.id;
const shouldShowMinified =
isCompactNotes &&
isFloating &&
! isSelected &&
thread.id !== 'new-note-thread';

if ( shouldShowMinified ) {
return (
<MinifiedThread
key={ thread.id }
thread={ thread }
calculatedOffset={ boardOffsets[ thread.id ] ?? 0 }
setHeights={ setHeights }
setBlockRef={ setBlockRef }
selectedThread={ selectedThread }
commentLastUpdated={ commentLastUpdated }
onExpand={ () => {
setNewNoteFormState( 'closed' );
setSelectedThread( thread.id );
if ( thread.blockClientId ) {
selectBlock( thread.blockClientId, null );
toggleBlockSpotlight(
thread.blockClientId,
true
);
}
} }
onKeyDown={ ( event ) =>
handleThreadNavigation( event, thread, false )
}
/>
);
}

return (
<Thread
key={ thread.id }
thread={ thread }
onAddReply={ onAddReply }
onCommentDelete={ handleDelete }
onEditComment={ onEditComment }
isSelected={ isSelected }
setSelectedThread={ setSelectedThread }
setNewNoteFormState={ setNewNoteFormState }
commentSidebarRef={ commentSidebarRef }
reflowComments={ reflowComments }
isFloating={ isFloating }
calculatedOffset={ boardOffsets[ thread.id ] ?? 0 }
setHeights={ setHeights }
setBlockRef={ setBlockRef }
selectedThread={ selectedThread }
commentLastUpdated={ commentLastUpdated }
newNoteFormState={ newNoteFormState }
onKeyDown={ ( event ) =>
handleThreadNavigation( event, thread, isSelected )
}
/>
);
} ) }
</>
);
}

/**
* Wrapper for MinifiedThreadIndicator that handles floating positioning.
*/
function MinifiedThread( {
thread,
calculatedOffset,
setHeights,
setBlockRef,
selectedThread,
commentLastUpdated,
onExpand,
onKeyDown,
} ) {
const { y, refs } = useFloatingThread( {
thread,
calculatedOffset,
setHeights,
setBlockRef,
selectedThread,
commentLastUpdated,
} );
Comment thread
Mamaduka marked this conversation as resolved.
Resolved

return (
<MinifiedThreadIndicator
thread={ thread }
y={ y }
refs={ refs }
onExpand={ onExpand }
onKeyDown={ onKeyDown }
/>
);
}

function Thread( {
thread,
onEditComment,
Expand Down
16 changes: 11 additions & 5 deletions packages/editor/src/components/collab-sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useViewportMatch } from '@wordpress/compose';
import { comment as commentIcon } from '@wordpress/icons';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { store as interfaceStore } from '@wordpress/interface';
import { store as preferencesStore } from '@wordpress/preferences';

/**
* Internal dependencies
Expand Down Expand Up @@ -42,6 +43,7 @@ function NotesSidebarContent( {
reflowComments,
commentLastUpdated,
isFloating = false,
isCompactNotes = false,
} ) {
const { onCreate, onEdit, onDelete } =
useBlockCommentsActions( reflowComments );
Expand Down Expand Up @@ -75,6 +77,7 @@ function NotesSidebarContent( {
reflowComments={ reflowComments }
commentLastUpdated={ commentLastUpdated }
isFloating={ isFloating }
isCompactNotes={ isCompactNotes }
/>
</VStack>
);
Expand All @@ -91,8 +94,8 @@ function NotesSidebar( { postId } ) {

const showFloatingSidebar = isLargeViewport;

const { clientId, blockCommentId, isDistractionFree } = useSelect(
( select ) => {
const { clientId, blockCommentId, isDistractionFree, isCompactNotes } =
useSelect( ( select ) => {
const {
getBlockAttributes,
getSelectedBlockClientId,
Expand All @@ -105,10 +108,12 @@ function NotesSidebar( { postId } ) {
? getBlockAttributes( _clientId )?.metadata?.noteId
: null,
isDistractionFree: getSettings().isDistractionFree,
isCompactNotes: !! select( preferencesStore ).get(
'core',
'compactNotes'
),
};
},
[]
);
}, [] );

const {
resultComments,
Expand Down Expand Up @@ -219,6 +224,7 @@ function NotesSidebar( { postId } ) {
backgroundColor,
} }
isFloating
isCompactNotes={ isCompactNotes }
/>
</PluginSidebar>
) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { useMemo, useState } from '@wordpress/element';
import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { dateI18n, getDate } from '@wordpress/date';

/**
* Internal dependencies
*/
import { getAvatarBorderColor, getCommentExcerpt } from './utils';

/**
* A compact avatar indicator for a note thread.
* Shows a single avatar that expands on hover to show author details.
*
* @param {Object} props Component props.
* @param {Object} props.thread The thread data.
* @param {number} props.y The vertical position from floating-ui.
* @param {Object} props.refs The refs object from floating-ui.
* @param {Function} props.onExpand Callback when indicator is clicked/activated.
* @param {Function} props.onKeyDown Callback for keyboard navigation.
*/
export default function MinifiedThreadIndicator( {
thread,
y,
refs,
onExpand,
onKeyDown,
} ) {
const [ isHovered, setIsHovered ] = useState( false );

const currentUserId = useSelect( ( select ) => {
return select( coreStore ).getCurrentUser()?.id;
}, [] );

// Get the last comment (most recent reply, or the thread itself if no replies).
const lastComment = useMemo( () => {
const replies = thread?.reply || [];
if ( replies.length > 0 ) {
return replies[ replies.length - 1 ];
}
return thread;
}, [ thread ] );

const commentExcerpt = getCommentExcerpt(
stripHTML( thread.content?.rendered ),
10
);

// Show unread indicator if last comment is from another user.
const hasUnread =
currentUserId && lastComment?.author !== currentUserId;
Comment thread
annezazu marked this conversation as resolved.
Resolved

// Format the time for display (e.g., "12:42 PM").
const formattedTime = lastComment?.date
? dateI18n( 'g:i A', getDate( lastComment.date ) )
Comment thread
annezazu marked this conversation as resolved.
Resolved
: '';

const handleClick = ( event ) => {
event.stopPropagation();
onExpand();
};

const handleKeyDown = ( event ) => {
if ( event.key === 'Enter' || event.key === ' ' ) {
event.preventDefault();
onExpand();
} else if ( onKeyDown ) {
// Handle arrow key navigation.
onKeyDown( event );
}
};

if ( ! lastComment?.author_avatar_urls ) {
return null;
}

return (
<div
className={ `editor-collab-sidebar-panel__minified-indicator${
isHovered ? ' is-expanded' : ''
}` }
id={ `comment-thread-${ thread.id }` }
onClick={ handleClick }
onKeyDown={ handleKeyDown }
onMouseEnter={ () => setIsHovered( true ) }
onMouseLeave={ () => setIsHovered( false ) }
onFocus={ () => setIsHovered( true ) }
onBlur={ () => setIsHovered( false ) }
tabIndex={ 0 }
role="treeitem"
aria-label={ sprintf(
// translators: %s: note excerpt
__( 'Note: %s' ),
commentExcerpt
) }
aria-expanded={ isHovered }
ref={ refs?.setFloating }
style={ { top: y } }
>
<img
src={ lastComment?.author_avatar_urls?.[ 48 ] }
alt={ lastComment?.author_name }
className="editor-collab-sidebar-panel__minified-avatar"
style={ {
borderColor: getAvatarBorderColor( lastComment?.author ),
} }
/>
{ isHovered && (
<>
<span className="editor-collab-sidebar-panel__minified-author-name">
{ lastComment?.author_name }
</span>
<span className="editor-collab-sidebar-panel__minified-time">
{ formattedTime }
</span>
</>
) }
{ hasUnread && (
<span className="editor-collab-sidebar-panel__minified-unread-dot" />
) }
</div>
);
}
46 changes: 46 additions & 0 deletions packages/editor/src/components/collab-sidebar/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,49 @@
}
}
}

// Minified Notes Mode
.editor-collab-sidebar-panel__minified-indicator {
position: absolute;
right: $grid-unit-20;
display: inline-flex;
align-items: center;
gap: $grid-unit-10;
padding: $grid-unit-20;
border-radius: $radius-large;
border: $border-width solid $gray-300;
background-color: $gray-100;
cursor: pointer;

&:focus {
outline: var(--wp-admin-border-width-focus) solid var(--wp-admin-theme-color);
outline-offset: calc(-1 * var(--wp-admin-border-width-focus));
}
}

.editor-collab-sidebar-panel__minified-avatar {
width: 20px;
height: 20px;
border-radius: $radius-round;
border-width: 1.5px;
border-style: solid;
background: $white;
box-sizing: border-box;
flex-shrink: 0;
}

.editor-collab-sidebar-panel__minified-author-name,
.editor-collab-sidebar-panel__minified-time {
font-size: 12px;
line-height: 16px;
color: $gray-700;
white-space: nowrap;
}

.editor-collab-sidebar-panel__minified-unread-dot {
width: 6px;
height: 6px;
border-radius: $radius-round;
background-color: #3858e9;
Comment thread
annezazu marked this conversation as resolved.
Resolved
flex-shrink: 0;
}
Loading
Loading