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

Create shared PanelHeading and CollapsibleFileList components (#22995)

GitOrigin-RevId: ffe524cc0ddf6a1cf532a50f37900b1747b2afee
Alf Eaton 1 год назад
Родитель
Сommit
53214d4222

+ 7 - 20
services/web/frontend/js/features/review-panel-new/components/review-panel-header.tsx

@@ -2,11 +2,10 @@ import { FC, memo, useState } from 'react'
 import { ReviewPanelResolvedThreadsButton } from './review-panel-resolved-threads-button'
 import { ReviewPanelTrackChangesMenu } from './review-panel-track-changes-menu'
 import ReviewPanelTrackChangesMenuButton from './review-panel-track-changes-menu-button'
-import MaterialIcon from '@/shared/components/material-icon'
 import { useLayoutContext } from '@/shared/context/layout-context'
-import SplitTestBadge from '@/shared/components/split-test-badge'
 import { useTranslation } from 'react-i18next'
 import getMeta from '@/utils/meta'
+import { PanelHeading } from '@/shared/components/panel-heading'
 
 const isReviewerRoleEnabled = getMeta('ol-isReviewerRoleEnabled')
 
@@ -18,25 +17,13 @@ const ReviewPanelHeader: FC = () => {
 
   return (
     <div className="review-panel-header">
-      <div className="review-panel-heading">
-        <div className="review-panel-label">
-          {t('review')}
-          <span className="review-panel-split-test-badge">
-            <SplitTestBadge
-              splitTestName="review-panel-redesign"
-              displayOnVariants={['enabled']}
-            />
-          </span>
-        </div>
+      <PanelHeading
+        title={t('review')}
+        handleClose={() => setReviewPanelOpen(false)}
+        splitTestName="review-panel-redesign"
+      >
         {isReviewerRoleEnabled && <ReviewPanelResolvedThreadsButton />}
-        <button
-          type="button"
-          className="btn review-panel-close-button"
-          onClick={() => setReviewPanelOpen(false)}
-        >
-          <MaterialIcon type="close" />
-        </button>
-      </div>
+      </PanelHeading>
       {!isReviewerRoleEnabled && (
         <div className="review-panel-tools">
           <ReviewPanelResolvedThreadsButton />

+ 7 - 14
services/web/frontend/js/features/review-panel-new/components/review-panel-overview-file.tsx

@@ -16,9 +16,9 @@ import {
 } from '../../../../../types/change'
 import { canAggregate } from '../utils/can-aggregate'
 
-import MaterialIcon from '@/shared/components/material-icon'
 import useOverviewFileCollapsed from '../hooks/use-overview-file-collapsed'
 import { useThreadsContext } from '../context/threads-context'
+import { CollapsibleFileHeader } from '@/shared/components/collapsible-file-header'
 
 export const ReviewPanelOverviewFile: FC<{
   doc: MainDocument
@@ -64,19 +64,12 @@ export const ReviewPanelOverviewFile: FC<{
   return (
     <>
       <div>
-        <button
-          type="button"
-          className="review-panel-overview-file-header"
-          onClick={toggleCollapsed}
-        >
-          <MaterialIcon
-            type={collapsed ? 'keyboard_arrow_right' : 'keyboard_arrow_down'}
-          />
-          {doc.doc.name}
-          <div className="review-panel-overview-file-entry-count">
-            {entries.length}
-          </div>
-        </button>
+        <CollapsibleFileHeader
+          name={doc.doc.name}
+          count={entries.length}
+          collapsed={collapsed}
+          toggleCollapsed={toggleCollapsed}
+        />
 
         {!collapsed && (
           <div className="review-panel-overview-file-entries">

+ 21 - 0
services/web/frontend/js/shared/components/collapsible-file-header.tsx

@@ -0,0 +1,21 @@
+import MaterialIcon from '@/shared/components/material-icon'
+import { Dispatch, FC, SetStateAction } from 'react'
+
+export const CollapsibleFileHeader: FC<{
+  name: string
+  count: number
+  collapsed: boolean
+  toggleCollapsed: Dispatch<SetStateAction<any>>
+}> = ({ name, count, collapsed, toggleCollapsed }) => (
+  <button
+    type="button"
+    className="collapsible-file-header"
+    onClick={toggleCollapsed}
+  >
+    <MaterialIcon
+      type={collapsed ? 'keyboard_arrow_right' : 'keyboard_arrow_down'}
+    />
+    {name}
+    <div className="collapsible-file-header-count">{count}</div>
+  </button>
+)

+ 38 - 0
services/web/frontend/js/shared/components/panel-heading.tsx

@@ -0,0 +1,38 @@
+import { FC } from 'react'
+import SplitTestBadge from '@/shared/components/split-test-badge'
+import MaterialIcon from '@/shared/components/material-icon'
+import { useTranslation } from 'react-i18next'
+
+export const PanelHeading: FC<{
+  title: string
+  splitTestName?: string
+  children?: React.ReactNode
+  handleClose(): void
+}> = ({ title, splitTestName, children, handleClose }) => {
+  const { t } = useTranslation()
+
+  return (
+    <div className="panel-heading">
+      <div className="panel-heading-label">
+        <span>{title}</span>
+        {splitTestName && (
+          <SplitTestBadge
+            splitTestName={splitTestName}
+            displayOnVariants={['enabled']}
+          />
+        )}
+      </div>
+
+      {children}
+
+      <button
+        type="button"
+        className="btn panel-heading-close-button"
+        aria-label={t('close')}
+        onClick={handleClose}
+      >
+        <MaterialIcon type="close" />
+      </button>
+    </div>
+  )
+}

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

@@ -498,7 +498,7 @@
     }
   }
 
-  .review-panel-overview-file-header {
+  .collapsible-file-header {
     all: unset;
     padding: 6px 8px;
     font-size: 14px;
@@ -524,7 +524,7 @@
     padding-bottom: 6px;
   }
 
-  .review-panel-overview-file-entry-count {
+  .collapsible-file-header-count {
     background-color: @neutral-20;
     padding: 2px 4px;
     margin-left: auto;

+ 2 - 0
services/web/frontend/stylesheets/bootstrap-5/components/all.scss

@@ -34,3 +34,5 @@
 @import 'recurly';
 @import 'dev-toolbar';
 @import 'tos';
+@import 'collapsible-file-header';
+@import 'panel-heading';

+ 18 - 0
services/web/frontend/stylesheets/bootstrap-5/components/collapsible-file-header.scss

@@ -0,0 +1,18 @@
+.collapsible-file-header {
+  all: unset;
+  padding: var(--spacing-03) var(--spacing-04);
+  font-size: var(--font-size-02);
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: var(--spacing-04);
+  box-sizing: border-box;
+  width: 100%;
+}
+
+.collapsible-file-header-count {
+  background-color: var(--neutral-20);
+  padding: var(--spacing-01) var(--spacing-02);
+  margin-left: auto;
+  border-radius: var(--border-radius-base);
+}

+ 31 - 0
services/web/frontend/stylesheets/bootstrap-5/components/panel-heading.scss

@@ -0,0 +1,31 @@
+.panel-heading {
+  display: flex;
+  align-items: center;
+  padding: var(--spacing-03) var(--spacing-02);
+  gap: 2px;
+}
+
+.panel-heading-label {
+  font-size: var(--font-size-02);
+  font-weight: bold;
+  margin: 0;
+  flex: 1;
+  text-align: start;
+  display: flex;
+  align-items: center;
+  gap: var(--spacing-02);
+}
+
+.panel-heading-close-button {
+  display: flex;
+  align-items: center;
+  border: none;
+  background-color: transparent;
+  color: var(--content-primary);
+  padding: var(--spacing-01);
+
+  &:hover,
+  &:focus {
+    background-color: var(--neutral-20);
+  }
+}

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

@@ -253,39 +253,6 @@
     }
   }
 
-  .review-panel-heading {
-    display: flex;
-    align-items: center;
-    padding: var(--spacing-03) var(--spacing-02);
-    gap: 2px;
-
-    .review-panel-label {
-      font-size: var(--font-size-02);
-      font-weight: bold;
-      margin: 0;
-      flex: 1;
-      text-align: start;
-    }
-
-    .review-panel-split-test-badge {
-      margin-left: var(--spacing-02);
-    }
-
-    .review-panel-close-button {
-      display: flex;
-      align-items: center;
-      border: none;
-      background-color: transparent;
-      color: var(--content-primary);
-      padding: var(--spacing-01);
-
-      &:hover,
-      &:focus {
-        background-color: var(--neutral-20);
-      }
-    }
-  }
-
   &.review-panel-resolved-comments {
     --bs-popover-border-width: 1px;
     --bs-popover-bg: var(--bg-light-secondary);
@@ -505,18 +472,6 @@
     }
   }
 
-  .review-panel-overview-file-header {
-    all: unset;
-    padding: var(--spacing-03) var(--spacing-04);
-    font-size: var(--font-size-02);
-    cursor: pointer;
-    display: flex;
-    align-items: center;
-    gap: var(--spacing-04);
-    box-sizing: border-box;
-    width: 100%;
-  }
-
   .review-panel-overfile-divider {
     border-bottom: 1px solid var(--border-divider);
     margin: var(--spacing-01) 0;
@@ -531,13 +486,6 @@
     padding-bottom: var(--spacing-03);
   }
 
-  .review-panel-overview-file-entry-count {
-    background-color: var(--neutral-20);
-    padding: var(--spacing-01) var(--spacing-02);
-    margin-left: auto;
-    border-radius: var(--border-radius-base);
-  }
-
   .review-panel-footer {
     position: fixed;
     height: 60px;