Przeglądaj źródła

Merge pull request #21815 from overleaf/td-bs5-references-search

[BS5] Migrate references search modal

GitOrigin-RevId: 65496840e32af09e5ae7351aa1789ebf5cac5083
Tim Down 1 rok temu
rodzic
commit
daaff1d9c6

+ 6 - 3
services/web/frontend/js/features/ui/components/bootstrap-5/form/form-control.tsx

@@ -1,13 +1,16 @@
 import { forwardRef } from 'react'
-import { Form, FormControlProps } from 'react-bootstrap-5'
+import {
+  Form,
+  FormControlProps as BS5FormControlProps,
+} from 'react-bootstrap-5'
 import classnames from 'classnames'
 
-type OLFormControlProps = FormControlProps & {
+type FormControlProps = BS5FormControlProps & {
   prepend?: React.ReactNode
   append?: React.ReactNode
 }
 
-const FormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
+const FormControl = forwardRef<HTMLInputElement, FormControlProps>(
   ({ prepend, append, className, ...props }, ref) => {
     if (prepend || append) {
       const wrapperClassNames = classnames('form-control-wrapper', {

+ 17 - 4
services/web/frontend/js/features/ui/components/ol/ol-form-control.tsx

@@ -3,11 +3,14 @@ import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
 import BS3FormControl from '@/features/ui/components/bootstrap-3/form/form-control'
 import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
+import OLSpinner from '@/features/ui/components/ol/ol-spinner'
+import Icon from '@/shared/components/icon'
 
 type OLFormControlProps = ComponentProps<typeof FormControl> & {
   bs3Props?: Record<string, unknown>
   'data-ol-dirty'?: unknown
   'main-field'?: any // For the CM6's benefit in the editor search panel
+  loading?: boolean
 }
 
 type BS3FormControlProps = ComponentProps<typeof BS3FormControl> & {
@@ -16,7 +19,7 @@ type BS3FormControlProps = ComponentProps<typeof BS3FormControl> & {
 
 const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
   (props, ref) => {
-    const { bs3Props, ...rest } = props
+    const { bs3Props, append, ...rest } = props
 
     // Use a callback so that the ref passed to the BS3 FormControl is stable
     const bs3InputRef = useCallback(
@@ -55,7 +58,6 @@ const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
       onBlur: rest.onBlur as BS3FormControlProps['onBlur'],
       onInvalid: rest.onInvalid as BS3FormControlProps['onInvalid'],
       prepend: rest.prepend,
-      append: rest.append,
       size: rest.htmlSize,
       'main-field': rest['main-field'],
       ...bs3Props,
@@ -69,8 +71,19 @@ const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
 
     return (
       <BootstrapVersionSwitcher
-        bs3={<BS3FormControl {...bs3FormControlProps} />}
-        bs5={<FormControl ref={ref} {...rest} />}
+        bs3={
+          <BS3FormControl
+            {...bs3FormControlProps}
+            append={rest.loading ? <Icon type="spinner" spin /> : append}
+          />
+        }
+        bs5={
+          <FormControl
+            ref={ref}
+            {...rest}
+            append={rest.loading ? <OLSpinner size="sm" /> : append}
+          />
+        }
       />
     )
   }

+ 16 - 5
services/web/frontend/js/features/ui/components/ol/ol-form-group.tsx

@@ -2,27 +2,38 @@ import { FormGroupProps } from 'react-bootstrap-5'
 import {
   FormGroup as BS3FormGroup,
   FormGroupProps as BS3FormGroupProps,
+  FormControl,
 } from 'react-bootstrap'
 import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
 import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
+import classNames from 'classnames'
 
 type OLFormGroupProps = FormGroupProps & {
-  bs3Props?: Record<string, unknown>
+  bs3Props?: {
+    withFeedback?: boolean
+    hiddenLabel?: boolean
+    validationState?: BS3FormGroupProps['validationState']
+  }
 }
 
 function OLFormGroup(props: OLFormGroupProps) {
   const { bs3Props, className, ...rest } = props
+  const { withFeedback, hiddenLabel, ...bs3PropsRest } = bs3Props || {}
 
   const bs3FormGroupProps: BS3FormGroupProps = {
-    children: rest.children,
     controlId: rest.controlId,
-    className,
-    ...bs3Props,
+    className: classNames(className, { 'hidden-label': hiddenLabel }),
+    ...bs3PropsRest,
   }
 
   return (
     <BootstrapVersionSwitcher
-      bs3={<BS3FormGroup {...bs3FormGroupProps} />}
+      bs3={
+        <BS3FormGroup {...bs3FormGroupProps}>
+          {rest.children}
+          {withFeedback ? <FormControl.Feedback /> : null}
+        </BS3FormGroup>
+      }
       bs5={<FormGroup className={className} {...rest} />}
     />
   )

+ 4 - 1
services/web/frontend/js/shared/components/beta-badge.tsx

@@ -3,6 +3,7 @@ import classnames from 'classnames'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import MaterialIcon from '@/shared/components/material-icon'
 import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
+import { bsVersion } from '@/features/utils/bootstrap-5'
 
 type TooltipProps = {
   id: string
@@ -30,7 +31,9 @@ const BetaBadge: FC<{
       }}
     >
       <a href={url} target="_blank" rel="noopener noreferrer">
-        <span className="sr-only">{tooltip.text}</span>
+        <span className={bsVersion({ bs5: 'visually-hidden', bs3: 'sr-only' })}>
+          {tooltip.text}
+        </span>
         <BootstrapVersionSwitcher
           bs3={<span className={classnames('badge', badgeClass)} />}
           bs5={

+ 1 - 5
services/web/frontend/stylesheets/app/editor.less

@@ -519,8 +519,7 @@ CodeMirror
       padding-left: 38px;
       padding-right: 38px;
       margin: auto;
-      background: white;
-      opacity: 0.95;
+      background: rgba(255, 255, 255, 0.95);
       border-radius: 8px;
       .message {
         margin-top: 15px;
@@ -531,9 +530,6 @@ CodeMirror
           text-align: left;
         }
       }
-      a.btn {
-        opacity: 1;
-      }
     }
   }
   .search-form {

+ 0 - 1
services/web/frontend/stylesheets/bootstrap-5/components/form.scss

@@ -147,7 +147,6 @@
     height: 100%;
     display: flex;
     align-items: center;
-    font-size: 0;
   }
 
   .form-control-start-icon {

+ 1 - 0
services/web/frontend/stylesheets/bootstrap-5/pages/all.scss

@@ -27,6 +27,7 @@
 @import 'editor/review-panel-new';
 @import 'editor/table-generator-column-width-modal';
 @import 'editor/math-preview';
+@import 'editor/references-search';
 @import 'website-redesign';
 @import 'group-settings';
 @import 'templates-v2';

+ 76 - 0
services/web/frontend/stylesheets/bootstrap-5/pages/editor/references-search.scss

@@ -0,0 +1,76 @@
+.references-search-modal {
+  .references-search-upgrade-prompt {
+    padding: var(--spacing-08);
+    padding-bottom: var(--spacing-11);
+
+    .upgrade-prompt {
+      text-align: center;
+      width: 400px;
+      padding: var(--spacing-06) var(--spacing-10);
+      margin: auto;
+      background: rgb($white, 0.95);
+      border-radius: var(--border-radius-medium);
+
+      .message {
+        margin-top: var(--spacing-06);
+
+        &.call-to-action {
+          font-weight: bold;
+        }
+
+        ul.upgrade-benefits {
+          text-align: left;
+
+          li {
+            display: flex;
+            align-items: center;
+          }
+        }
+      }
+    }
+  }
+
+  .notification {
+    margin-top: var(--spacing-05);
+    margin-bottom: 0;
+  }
+
+  // search result items list
+  .search-results {
+    font-size: var(--font-size-01);
+
+    .no-results-message,
+    .too-many-results-message {
+      font-size: var(--font-size-03);
+    }
+
+    .search-results-scroll-container {
+      max-height: calc(100vh - 225px);
+      overflow-y: auto;
+    }
+
+    .search-result-hit {
+      &:hover {
+        cursor: pointer;
+      }
+
+      border-bottom: 1px solid var(--border-divider);
+      padding: var(--spacing-04);
+
+      &:last-child {
+        border-bottom: 1px solid transparent;
+      }
+
+      border-left: var(--spacing-02) solid transparent;
+
+      &.selected-search-result-hit {
+        color: var(--content-positive);
+      }
+
+      .hit-title {
+        font-size: var(--font-size-03);
+        font-style: italic;
+      }
+    }
+  }
+}

+ 6 - 0
services/web/frontend/stylesheets/components/forms.less

@@ -159,6 +159,7 @@ output {
     height: auto;
     border-radius: @border-radius-base;
   }
+
   // Smaller border-radius for `select` inputs
   select& {
     border-radius: @border-radius-base;
@@ -295,6 +296,11 @@ input[type='checkbox'],
     line-height: @input-height-base;
     text-align: center;
   }
+
+  // Position the feedback inside the input element when there's no label
+  &.hidden-label .form-control-feedback {
+    margin-top: -(@line-height-computed + 5);
+  }
 }
 
 .has-feedback-left {