Просмотр исходного кода

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
Domagoj Kriskovic 1 год назад
Родитель
Сommit
8b0b923063

+ 19 - 15
services/web/frontend/js/features/review-panel-new/components/review-panel-change.tsx

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

+ 62 - 36
services/web/frontend/js/features/review-panel-new/components/review-panel-expandable-content.tsx

@@ -1,24 +1,34 @@
-import { FC, useCallback, useEffect, useRef, useState } from 'react'
-import classNames from 'classnames'
+import { FC, useCallback, useRef, useState } from 'react'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import { useTranslation } from 'react-i18next'
+import classNames from 'classnames'
 
-export const ExpandableContent: FC<{ className?: string }> = ({
-  children,
+export const ExpandableContent: FC<{
+  className?: string
+  content: string
+  contentLimit?: number
+  newLineCharsLimit?: number
+  checkNewLines?: boolean
+  inline?: boolean
+}> = ({
+  content,
   className,
+  contentLimit = 50,
+  newLineCharsLimit = 3,
+  checkNewLines = true,
+  inline = false,
 }) => {
   const { t } = useTranslation()
   const contentRef = useRef<HTMLDivElement>(null)
   const [isExpanded, setIsExpanded] = useState(false)
-  const [isOverflowing, setIsOverflowing] = useState(false)
-
-  useEffect(() => {
-    if (contentRef.current) {
-      setIsOverflowing(
-        contentRef.current.scrollHeight > contentRef.current.clientHeight
+  const limit = checkNewLines
+    ? Math.min(
+        contentLimit,
+        indexOfNthLine(content, newLineCharsLimit) ?? Infinity
       )
-    }
-  }, [])
+    : contentLimit
+
+  const isOverflowing = content.length > limit
 
   const handleShowMore = useCallback(() => {
     setIsExpanded(true)
@@ -35,38 +45,54 @@ export const ExpandableContent: FC<{ className?: string }> = ({
   }, [])
 
   return (
-    <div>
+    <>
       <div
         ref={contentRef}
-        className={classNames(
-          'review-panel-content-expandable',
-          {
-            'review-panel-content-expanded': isExpanded,
-          },
-          className
-        )}
+        className={classNames('review-panel-expandable-content', className)}
       >
-        {children}
+        {isExpanded ? content : content.slice(0, limit)}
+        {isOverflowing && !isExpanded && '...'}
       </div>
-      {isExpanded ? (
-        <OLButton
-          variant="link"
-          className="btn-inline-link"
-          onClick={handleShowLess}
-        >
-          {t('show_less')}
-        </OLButton>
-      ) : (
-        isOverflowing && (
+      <div
+        className={classNames('review-panel-expandable-links', {
+          'review-panel-expandable-inline': inline,
+        })}
+      >
+        {isExpanded ? (
           <OLButton
             variant="link"
             className="btn-inline-link"
-            onClick={handleShowMore}
+            onClick={handleShowLess}
           >
-            {t('show_more')}
+            {t('show_less')}
           </OLButton>
-        )
-      )}
-    </div>
+        ) : (
+          isOverflowing && (
+            <OLButton
+              variant="link"
+              className="btn-inline-link"
+              onClick={handleShowMore}
+            >
+              {t('show_more')}
+            </OLButton>
+          )
+        )}
+      </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
+}

+ 5 - 3
services/web/frontend/js/features/review-panel-new/components/review-panel-message.tsx

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

+ 5 - 3
services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-thread.tsx

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

+ 16 - 9
services/web/frontend/stylesheets/app/editor/review-panel-new.less

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

+ 17 - 9
services/web/frontend/stylesheets/bootstrap-5/pages/editor/review-panel-new.scss

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