Răsfoiți Sursa

Add toggle for workbench position (#30873)

GitOrigin-RevId: 622e7e8ad2b5493d4c55abc8392fb050a629b015
Alf Eaton 8 luni în urmă
părinte
comite
46435ab8b4

+ 2 - 0
services/web/frontend/extracted-translations.json

@@ -1117,6 +1117,8 @@
   "more_editor_toolbar_item": "",
   "more_info": "",
   "more_options": "",
+  "move_to_the_left": "",
+  "move_to_the_right": "",
   "my_library": "",
   "n_items": "",
   "n_items_plural": "",

+ 1 - 1
services/web/frontend/js/features/ide-redesign/components/rail/rail-panel-header.tsx

@@ -10,7 +10,7 @@ export default function RailPanelHeader({
   onClose,
 }: {
   title: React.ReactNode
-  actions?: React.ReactNode[]
+  actions?: React.ReactElement
   onClose?: () => void
 }) {
   const { t } = useTranslation()

+ 6 - 7
services/web/frontend/js/features/ide-redesign/components/rail/rail-tab.tsx

@@ -1,7 +1,7 @@
 import OLTooltip from '@/shared/components/ol/ol-tooltip'
 import MaterialIcon from '@/shared/components/material-icon'
 import classNames from 'classnames'
-import { forwardRef, ReactElement } from 'react'
+import { ComponentProps, forwardRef, ReactElement } from 'react'
 import { NavLink } from 'react-bootstrap'
 import { RailElement } from '../../utils/rail-types'
 
@@ -9,13 +9,12 @@ const RailTab = forwardRef<
   HTMLAnchorElement,
   {
     icon: RailElement['icon']
-    eventKey: string
+    eventKey?: string
     open: boolean
     indicator?: ReactElement
     title: string
-    disabled?: boolean
-  }
->(({ icon, eventKey, open, indicator, title, disabled = false }, ref) => {
+  } & ComponentProps<'button'>
+>(({ icon, eventKey, className, open, indicator, title, ...props }, ref) => {
   return (
     <OLTooltip
       id={`rail-tab-tooltip-${eventKey}`}
@@ -23,12 +22,12 @@ const RailTab = forwardRef<
       overlayProps={{ delay: 0, placement: 'right' }}
     >
       <NavLink
+        {...props}
         ref={ref}
         eventKey={eventKey}
-        className={classNames('ide-rail-tab-link', {
+        className={classNames('ide-rail-tab-link', className, {
           'open-rail': open,
         })}
-        disabled={disabled}
       >
         <RailTabIcon icon={icon} title={title} open={open} />
         {indicator}

+ 36 - 13
services/web/frontend/js/features/ide-redesign/components/rail/rail.tsx

@@ -32,6 +32,7 @@ import EditorTourThemeTooltip from '../editor-tour/editor-tour-theme-tooltip'
 import EditorTourGotQuestionsTooltip from '../editor-tour/editor-tour-got-questions'
 import { shouldIncludeElement } from '../../utils/rail-utils'
 import { useEditorContext } from '@/shared/context/editor-context'
+import useEventListener from '@/shared/hooks/use-event-listener'
 
 const moduleRailEntries = (
   importOverleafModules('railEntries') as {
@@ -39,6 +40,7 @@ const moduleRailEntries = (
     path: string
   }[]
 ).map(({ import: { default: element } }) => element)
+
 const moduleRailPopovers = (
   importOverleafModules('railPopovers') as {
     import: {
@@ -56,7 +58,8 @@ const moduleRailPopovers = (
 export const RailLayout = () => {
   const { sendEvent } = useEditorAnalytics()
   const { t } = useTranslation()
-  const { selectedTab, openTab, isOpen, togglePane } = useRailContext()
+  const { selectedTab, openTab, isOpen, setIsOpen, togglePane, selectTab } =
+    useRailContext()
   const { features } = useProjectContext()
   const { isRestrictedTokenMember } = useEditorContext()
   const gitBridgeEnabled = getMeta('ol-gitBridgeEnabled')
@@ -71,6 +74,23 @@ export const RailLayout = () => {
   const fileTreeRef = useRef<HTMLAnchorElement>(null)
   const settingsRef = useRef<HTMLButtonElement>(null)
 
+  useEventListener(
+    'ui:select-rail-tab',
+    useCallback(
+      (event: Event) => {
+        const {
+          detail: { tab, open },
+        } = event as CustomEvent<{
+          tab: RailTabKey
+          open: boolean
+        }>
+        selectTab(tab)
+        setIsOpen(open)
+      },
+      [selectTab, setIsOpen]
+    )
+  )
+
   const railTabs: RailElement[] = useMemo(
     () => [
       {
@@ -253,18 +273,21 @@ export const RailLayout = () => {
           <div className="ide-rail-tabs-wrapper" ref={tabWrapperRef}>
             {tabsInRail
               .filter(shouldIncludeElement)
-              .map(({ icon, key, indicator, title, disabled, ref }) => (
-                <RailTab
-                  open={isOpen && selectedTab === key}
-                  key={key}
-                  eventKey={key}
-                  icon={icon}
-                  indicator={indicator}
-                  title={title}
-                  disabled={disabled}
-                  ref={ref}
-                />
-              ))}
+              .map(({ icon, key, indicator, title, disabled, ref, tab }) => {
+                const Component = tab ?? RailTab
+                return (
+                  <Component
+                    open={isOpen && selectedTab === key}
+                    key={key}
+                    eventKey={key}
+                    icon={icon}
+                    indicator={indicator}
+                    title={title}
+                    disabled={disabled}
+                    ref={ref}
+                  />
+                )
+              })}
             <RailActionElement key="more-options" action={moreOptionsAction} />
           </div>
           <nav aria-label={t('help_editor_settings')}>

+ 10 - 0
services/web/frontend/js/features/ide-redesign/contexts/rail-context.tsx

@@ -41,6 +41,7 @@ const RailContext = createContext<
       activeModal: RailModalKey | null
       setActiveModal: Dispatch<SetStateAction<RailModalKey | null>>
       openTab: (tab: RailTabKey) => void
+      selectTab: (tab: RailTabKey) => void
     }
   | undefined
 >(undefined)
@@ -92,6 +93,13 @@ export const RailProvider: FC<React.PropsWithChildren> = ({ children }) => {
     }
   }, [isOpen, selectedTab])
 
+  const selectTab = useCallback(
+    (tab: RailTabKey) => {
+      setSelectedTab(tab)
+    },
+    [setSelectedTab]
+  )
+
   const openTab = useCallback(
     (tab: RailTabKey) => {
       setSelectedTab(tab)
@@ -146,6 +154,7 @@ export const RailProvider: FC<React.PropsWithChildren> = ({ children }) => {
       activeModal,
       setActiveModal,
       openTab,
+      selectTab,
     }),
     [
       selectedTab,
@@ -160,6 +169,7 @@ export const RailProvider: FC<React.PropsWithChildren> = ({ children }) => {
       activeModal,
       setActiveModal,
       openTab,
+      selectTab,
     ]
   )
 

+ 2 - 0
services/web/frontend/js/features/ide-redesign/utils/rail-types.ts

@@ -1,6 +1,7 @@
 import { AvailableUnfilledIcon } from '@/shared/components/material-icon'
 import { RailTabKey } from '../contexts/rail-context'
 import { FC, ReactElement } from 'react'
+import RailTab from '@/features/ide-redesign/components/rail/rail-tab'
 
 export type CustomRailTabIcon = FC<{ open: boolean; title: string }>
 
@@ -14,4 +15,5 @@ export type RailElement = {
   disabled?: boolean
   mountOnFirstLoad?: boolean
   ref?: React.RefObject<HTMLAnchorElement>
+  tab?: typeof RailTab
 }

+ 1 - 1
services/web/frontend/js/features/review-panel/components/review-panel-header.tsx

@@ -16,7 +16,7 @@ const ReviewPanelHeader: FC = () => {
       {newEditor ? (
         <RailPanelHeader
           title={t('review')}
-          actions={[<ReviewPanelResolvedThreadsButton key="resolve-threads" />]}
+          actions={<ReviewPanelResolvedThreadsButton key="resolve-threads" />}
         />
       ) : (
         <PanelHeading title={t('review')} handleClose={closeReviewPanel}>

+ 17 - 0
services/web/frontend/stylesheets/pages/editor/rail.scss

@@ -200,3 +200,20 @@ body {
   background-color: black;
   border-radius: var(--border-radius-base);
 }
+
+.separated-rail-tab {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  margin-top: 8px;
+  isolation: isolate;
+}
+
+.separated-rail-tab::before {
+  display: inline-block;
+  content: '';
+  border-top: 1px solid var(--border-divider);
+  width: 100%;
+  transform: translateY(-12px);
+}

+ 2 - 0
services/web/locales/en.json

@@ -1440,6 +1440,8 @@
   "more_project_collaborators": "<0>More</0> project <0>collaborators</0>",
   "more_than_one_kind_of_snippet_was_requested": "The link to open this content on Overleaf included some invalid parameters. If this keeps happening for links on a particular site, please report this to them.",
   "most_popular_uppercase": "Most popular",
+  "move_to_the_left": "Move to the left",
+  "move_to_the_right": "Move to the right",
   "must_be_at_least_n_characters": "Must be at least __n__ characters. Avoid common passwords.",
   "must_be_email_address": "Must be an email address.",
   "must_be_purchased_online": "Must be purchased online",