Fix "show more/less" options in new review panel (#21700)

* Fix "show all/less" options in new review panel

* added newLineCharsLimit, inline options

* fix scss lint

GitOrigin-RevId: 98f29c76d4efda225515162cde0961e55acd5545
This commit is contained in:
Domagoj Kriskovic 2024-11-08 15:23:57 +01:00 committed by Copybot
parent 595c60327e
commit 8b0b923063
6 changed files with 124 additions and 75 deletions

View file

@ -15,15 +15,7 @@ import { useChangesUsersContext } from '../context/changes-users-context'
import { ReviewPanelChangeUser } from './review-panel-change-user' import { ReviewPanelChangeUser } from './review-panel-change-user'
import { ReviewPanelEntry } from './review-panel-entry' import { ReviewPanelEntry } from './review-panel-entry'
import { useModalsContext } from '@/features/ide-react/context/modals-context' import { useModalsContext } from '@/features/ide-react/context/modals-context'
import { ExpandableContent } from './review-panel-expandable-content'
const TEXT_CHAR_LIMIT = 50
const truncateText = (text: string) => {
if (text.length > TEXT_CHAR_LIMIT) {
return text.slice(0, TEXT_CHAR_LIMIT) + '...'
}
return text
}
export const ReviewPanelChange = memo<{ export const ReviewPanelChange = memo<{
change: Change<EditOperation> change: Change<EditOperation>
@ -172,18 +164,27 @@ export const ReviewPanelChange = memo<{
<span> <span>
{t('aggregate_changed')}:{' '} {t('aggregate_changed')}:{' '}
<del className="review-panel-content-highlight"> <del className="review-panel-content-highlight">
{truncateText(aggregate.op.d)} <ExpandableContent
inline
content={aggregate.op.d}
checkNewLines={false}
/>
</del>{' '} </del>{' '}
{t('aggregate_to')}{' '} {t('aggregate_to')}{' '}
<ins className="review-panel-content-highlight"> <ExpandableContent
{truncateText(change.op.i)} inline
</ins> content={change.op.i}
checkNewLines={false}
/>
</span> </span>
) : ( ) : (
<span> <span>
{t('tracked_change_added')}:&nbsp; {t('tracked_change_added')}:&nbsp;
<ins className="review-panel-content-highlight"> <ins className="review-panel-content-highlight">
{truncateText(change.op.i)} <ExpandableContent
content={change.op.i}
checkNewLines={false}
/>
</ins> </ins>
</span> </span>
)} )}
@ -200,7 +201,10 @@ export const ReviewPanelChange = memo<{
<span> <span>
{t('tracked_change_deleted')}:&nbsp; {t('tracked_change_deleted')}:&nbsp;
<del className="review-panel-content-highlight"> <del className="review-panel-content-highlight">
{truncateText(change.op.d)} <ExpandableContent
content={change.op.d}
checkNewLines={false}
/>
</del> </del>
</span> </span>
</> </>

View file

@ -1,24 +1,34 @@
import { FC, useCallback, useEffect, useRef, useState } from 'react' import { FC, useCallback, useRef, useState } from 'react'
import classNames from 'classnames'
import OLButton from '@/features/ui/components/ol/ol-button' import OLButton from '@/features/ui/components/ol/ol-button'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import classNames from 'classnames'
export const ExpandableContent: FC<{ className?: string }> = ({ export const ExpandableContent: FC<{
children, className?: string
content: string
contentLimit?: number
newLineCharsLimit?: number
checkNewLines?: boolean
inline?: boolean
}> = ({
content,
className, className,
contentLimit = 50,
newLineCharsLimit = 3,
checkNewLines = true,
inline = false,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const contentRef = useRef<HTMLDivElement>(null) const contentRef = useRef<HTMLDivElement>(null)
const [isExpanded, setIsExpanded] = useState(false) const [isExpanded, setIsExpanded] = useState(false)
const [isOverflowing, setIsOverflowing] = useState(false) const limit = checkNewLines
? Math.min(
useEffect(() => { contentLimit,
if (contentRef.current) { indexOfNthLine(content, newLineCharsLimit) ?? Infinity
setIsOverflowing(
contentRef.current.scrollHeight > contentRef.current.clientHeight
) )
} : contentLimit
}, [])
const isOverflowing = content.length > limit
const handleShowMore = useCallback(() => { const handleShowMore = useCallback(() => {
setIsExpanded(true) setIsExpanded(true)
@ -35,19 +45,19 @@ export const ExpandableContent: FC<{ className?: string }> = ({
}, []) }, [])
return ( return (
<div> <>
<div <div
ref={contentRef} ref={contentRef}
className={classNames( className={classNames('review-panel-expandable-content', className)}
'review-panel-content-expandable',
{
'review-panel-content-expanded': isExpanded,
},
className
)}
> >
{children} {isExpanded ? content : content.slice(0, limit)}
{isOverflowing && !isExpanded && '...'}
</div> </div>
<div
className={classNames('review-panel-expandable-links', {
'review-panel-expandable-inline': inline,
})}
>
{isExpanded ? ( {isExpanded ? (
<OLButton <OLButton
variant="link" variant="link"
@ -68,5 +78,21 @@ export const ExpandableContent: FC<{ className?: string }> = ({
) )
)} )}
</div> </div>
</>
) )
} }
function indexOfNthLine(content: string, n: number) {
if (n < 1) return null
let line = 0
for (let i = 0; i < content.length; i++) {
if (content[i] === '\n') {
line++
if (line === n) {
return i
}
}
}
return null
}

View file

@ -112,9 +112,11 @@ export const ReviewPanelMessage: FC<{
autoFocus // eslint-disable-line jsx-a11y/no-autofocus autoFocus // eslint-disable-line jsx-a11y/no-autofocus
/> />
) : ( ) : (
<ExpandableContent className="review-panel-comment-body"> <ExpandableContent
{message.content} className="review-panel-comment-body"
</ExpandableContent> checkNewLines
content={message.content}
/>
)} )}
{deleting && ( {deleting && (

View file

@ -97,9 +97,11 @@ export const ReviewPanelResolvedThread: FC<{
<div className="review-panel-resolved-comment-quoted-text-label"> <div className="review-panel-resolved-comment-quoted-text-label">
{t('quoted_text')} {t('quoted_text')}
</div> </div>
<ExpandableContent className="review-panel-resolved-comment-quoted-text-quote"> <ExpandableContent
{comment?.op.c} className="review-panel-resolved-comment-quoted-text-quote"
</ExpandableContent> content={comment?.op.c}
checkNewLines
/>
</div> </div>
<ReviewPanelCommentContent comment={comment} isResolved /> <ReviewPanelCommentContent comment={comment} isResolved />

View file

@ -361,19 +361,26 @@
font-size: @font-size-02; font-size: @font-size-02;
color: @content-primary; color: @content-primary;
overflow-wrap: anywhere; overflow-wrap: anywhere;
white-space: pre-wrap;
} }
.review-panel-content-expandable { .review-panel-expandable-content {
display: -webkit-box; display: inline;
text-overflow: ellipsis; padding-right: var(--spacing-02);
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
} }
.review-panel-content-expanded { .review-panel-expandable-inline {
display: block; display: inline;
}
.review-panel-expandable-links {
.btn-inline-link {
text-decoration: none;
line-height: 1;
}
.btn-inline-link:hover {
text-decoration: underline;
}
} }
.review-panel-comment-input { .review-panel-comment-input {

View file

@ -366,19 +366,27 @@
font-size: var(--font-size-02); font-size: var(--font-size-02);
color: var(--content-primary); color: var(--content-primary);
overflow-wrap: anywhere; overflow-wrap: anywhere;
white-space: pre-wrap;
} }
.review-panel-content-expandable { .review-panel-expandable-content {
display: -webkit-box; display: inline;
text-overflow: ellipsis; padding-right: var(--spacing-02);
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
} }
.review-panel-content-expanded { .review-panel-expandable-inline {
display: block; display: inline;
}
.review-panel-expandable-links {
.btn-inline-link {
text-decoration: none;
line-height: 1;
}
.btn-inline-link:hover {
text-decoration: underline;
}
} }
.review-panel-comment-input { .review-panel-comment-input {