Răsfoiți Sursa

Remove Bootstrap 3 code from IDE page components (#23061)

GitOrigin-RevId: b41aff10672bf96e892de0be396a69eb25e2443b
Alf Eaton 1 an în urmă
părinte
comite
2147f1d53d
100 a modificat fișierele cu 760 adăugiri și 2315 ștergeri
  1. 4 4
      services/web/.storybook/preview.tsx
  2. 2 2
      services/web/.storybook/utils/with-bootstrap-switcher.tsx
  3. 1 0
      services/web/cypress/support/component.ts
  4. 1 0
      services/web/cypress/support/ct/window.ts
  5. 2 7
      services/web/cypress/support/shared/commands/compile.ts
  6. 0 4
      services/web/frontend/extracted-translations.json
  7. 3 13
      services/web/frontend/js/features/chat/components/chat-pane.tsx
  8. 1 5
      services/web/frontend/js/features/chat/components/message-input.tsx
  9. 13 40
      services/web/frontend/js/features/clone-project-modal/components/clone-project-tag.tsx
  10. 1 8
      services/web/frontend/js/features/dictionary/components/dictionary-modal-content.tsx
  11. 2 10
      services/web/frontend/js/features/editor-left-menu/components/download-pdf.tsx
  12. 1 6
      services/web/frontend/js/features/editor-left-menu/components/download-source.tsx
  13. 18 46
      services/web/frontend/js/features/editor-left-menu/components/editor-left-menu.tsx
  14. 1 8
      services/web/frontend/js/features/editor-left-menu/components/left-menu-button.tsx
  15. 0 1
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-dictionary.tsx
  16. 8 18
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-menu-select.tsx
  17. 4 17
      services/web/frontend/js/features/editor-navigation-toolbar/components/back-to-projects-button.tsx
  18. 5 18
      services/web/frontend/js/features/editor-navigation-toolbar/components/chat-toggle-button.jsx
  19. 1 6
      services/web/frontend/js/features/editor-navigation-toolbar/components/history-toggle-button.jsx
  20. 99 283
      services/web/frontend/js/features/editor-navigation-toolbar/components/layout-dropdown-button.tsx
  21. 1 11
      services/web/frontend/js/features/editor-navigation-toolbar/components/menu-button.jsx
  22. 23 59
      services/web/frontend/js/features/editor-navigation-toolbar/components/online-users-widget.jsx
  23. 1 6
      services/web/frontend/js/features/editor-navigation-toolbar/components/project-name-editable-label.tsx
  24. 1 6
      services/web/frontend/js/features/editor-navigation-toolbar/components/share-project-button.jsx
  25. 6 17
      services/web/frontend/js/features/editor-navigation-toolbar/components/toolbar-header.jsx
  26. 1 5
      services/web/frontend/js/features/editor-navigation-toolbar/components/track-changes-toggle-button.jsx
  27. 1 6
      services/web/frontend/js/features/editor-navigation-toolbar/components/upgrade-prompt.jsx
  28. 19 48
      services/web/frontend/js/features/file-tree/components/file-tree-context-menu.tsx
  29. 2 3
      services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-body.jsx
  30. 0 1
      services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-footer.jsx
  31. 1 6
      services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-mode.jsx
  32. 15 32
      services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-import-from-project.tsx
  33. 15 40
      services/web/frontend/js/features/file-tree/components/file-tree-folder-icons.tsx
  34. 9 30
      services/web/frontend/js/features/file-tree/components/file-tree-icon.tsx
  35. 41 76
      services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu-items.tsx
  36. 1 6
      services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu.tsx
  37. 5 38
      services/web/frontend/js/features/file-tree/components/file-tree-toolbar.tsx
  38. 1 6
      services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-create-folder.jsx
  39. 1 6
      services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-delete.jsx
  40. 4 5
      services/web/frontend/js/features/file-tree/util/icon-type-from-name.ts
  41. 1 6
      services/web/frontend/js/features/file-view/components/file-view-header.tsx
  42. 5 19
      services/web/frontend/js/features/file-view/components/file-view-icons.jsx
  43. 1 9
      services/web/frontend/js/features/file-view/components/file-view-refresh-button.tsx
  44. 0 5
      services/web/frontend/js/features/history/components/change-list/add-label-modal.tsx
  45. 0 4
      services/web/frontend/js/features/history/components/change-list/all-history-list.tsx
  46. 2 75
      services/web/frontend/js/features/history/components/change-list/dropdown/actions-dropdown.tsx
  47. 1 13
      services/web/frontend/js/features/history/components/change-list/dropdown/history-dropdown.tsx
  48. 1 4
      services/web/frontend/js/features/history/components/change-list/dropdown/menu-item/compare.tsx
  49. 1 8
      services/web/frontend/js/features/history/components/change-list/dropdown/menu-item/download.tsx
  50. 1 8
      services/web/frontend/js/features/history/components/change-list/dropdown/menu-item/restore-project.tsx
  51. 1 5
      services/web/frontend/js/features/history/components/change-list/history-version.tsx
  52. 1 5
      services/web/frontend/js/features/history/components/change-list/label-list-item.tsx
  53. 0 5
      services/web/frontend/js/features/history/components/change-list/tag-tooltip.tsx
  54. 2 3
      services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx
  55. 0 1
      services/web/frontend/js/features/history/components/diff-view/modals/restore-project-modal.tsx
  56. 0 4
      services/web/frontend/js/features/history/components/diff-view/toolbar/toolbar-restore-file-button.tsx
  57. 0 4
      services/web/frontend/js/features/history/components/diff-view/toolbar/toolbar-restore-file-to-version-button.tsx
  58. 3 16
      services/web/frontend/js/features/history/components/file-tree/history-file-tree-doc.tsx
  59. 16 42
      services/web/frontend/js/features/history/components/file-tree/history-file-tree-folder.tsx
  60. 0 1
      services/web/frontend/js/features/ide-react/components/alerts/alerts.tsx
  61. 0 1
      services/web/frontend/js/features/ide-react/components/alerts/lost-connection-alert.tsx
  62. 2 31
      services/web/frontend/js/features/pdf-preview/components/detach-compile-button.tsx
  63. 1 14
      services/web/frontend/js/features/pdf-preview/components/pdf-clear-cache-button.tsx
  64. 2 16
      services/web/frontend/js/features/pdf-preview/components/pdf-code-check-failed-notice.tsx
  65. 115 249
      services/web/frontend/js/features/pdf-preview/components/pdf-compile-button.tsx
  66. 13 39
      services/web/frontend/js/features/pdf-preview/components/pdf-download-files-button.tsx
  67. 33 87
      services/web/frontend/js/features/pdf-preview/components/pdf-file-list.tsx
  68. 2 13
      services/web/frontend/js/features/pdf-preview/components/pdf-hybrid-code-check-button.tsx
  69. 1 6
      services/web/frontend/js/features/pdf-preview/components/pdf-hybrid-download-button.tsx
  70. 1 6
      services/web/frontend/js/features/pdf-preview/components/pdf-hybrid-logs-button.tsx
  71. 0 4
      services/web/frontend/js/features/pdf-preview/components/pdf-log-entry-raw-content.tsx
  72. 0 2
      services/web/frontend/js/features/pdf-preview/components/pdf-preview-error.tsx
  73. 5 12
      services/web/frontend/js/features/pdf-preview/components/pdf-preview-hybrid-toolbar.tsx
  74. 7 56
      services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.tsx
  75. 109 210
      services/web/frontend/js/features/pdf-preview/components/pdf-zoom-dropdown.tsx
  76. 1 6
      services/web/frontend/js/features/pdf-preview/components/stop-on-first-error-prompt.tsx
  77. 2 15
      services/web/frontend/js/features/pdf-preview/components/switch-to-editor-button.tsx
  78. 0 1
      services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt-new.tsx
  79. 1 11
      services/web/frontend/js/features/preview/components/preview-log-entry-header.tsx
  80. 2 13
      services/web/frontend/js/features/preview/components/preview-logs-pane-max-entries.jsx
  81. 29 61
      services/web/frontend/js/features/review-panel-new/components/review-panel-comment-options.tsx
  82. 1 10
      services/web/frontend/js/features/review-panel-new/components/review-panel-more-comments-button.tsx
  83. 1 6
      services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-button.tsx
  84. 1 10
      services/web/frontend/js/features/review-panel-new/components/review-panel-track-changes-menu-button.tsx
  85. 0 3
      services/web/frontend/js/features/share-project-modal/components/add-collaborators.jsx
  86. 11 40
      services/web/frontend/js/features/share-project-modal/components/edit-member.tsx
  87. 2 12
      services/web/frontend/js/features/share-project-modal/components/invite.jsx
  88. 3 13
      services/web/frontend/js/features/share-project-modal/components/link-sharing.jsx
  89. 1 6
      services/web/frontend/js/features/share-project-modal/components/owner-info.jsx
  90. 29 88
      services/web/frontend/js/features/share-project-modal/components/select-collaborators.jsx
  91. 6 14
      services/web/frontend/js/features/share-project-modal/components/share-project-modal-content.tsx
  92. 6 14
      services/web/frontend/js/features/share-project-modal/components/transfer-ownership-modal.jsx
  93. 1 6
      services/web/frontend/js/features/share-project-modal/components/view-member.jsx
  94. 7 34
      services/web/frontend/js/features/source-editor/components/codemirror-search-form.tsx
  95. 2 10
      services/web/frontend/js/features/source-editor/components/command-tooltip/href-tooltip.tsx
  96. 1 6
      services/web/frontend/js/features/source-editor/components/command-tooltip/include-tooltip.tsx
  97. 1 6
      services/web/frontend/js/features/source-editor/components/command-tooltip/input-tooltip.tsx
  98. 1 6
      services/web/frontend/js/features/source-editor/components/command-tooltip/ref-tooltip.tsx
  99. 1 6
      services/web/frontend/js/features/source-editor/components/command-tooltip/url-tooltip.tsx
  100. 8 32
      services/web/frontend/js/features/source-editor/components/figure-modal/figure-modal-footer.tsx

+ 4 - 4
services/web/.storybook/preview.tsx

@@ -126,8 +126,8 @@ const preview: Preview = {
       // render stories in iframes, to isolate modals
       inlineStories: false,
     },
-    // Default to Bootstrap 3 styles
-    bootstrap5: false,
+    // Default to Bootstrap 5 styles
+    bootstrap5: true,
   },
   globalTypes: {
     theme: {
@@ -166,10 +166,10 @@ const preview: Preview = {
       const { bootstrap3Style, bootstrap5Style } = context.loaded
       const bootstrapVersion = Number(
         context.args[bootstrapVersionArg] ||
-          (context.parameters.bootstrap5 ? 5 : 3)
+          (context.parameters.bootstrap5 === false ? 3 : 5)
       ) as 3 | 5
       const activeStyle =
-        bootstrapVersion === 5 ? bootstrap5Style : bootstrap3Style
+        bootstrapVersion === 3 ? bootstrap3Style : bootstrap5Style
 
       resetMeta(bootstrapVersion)
 

+ 2 - 2
services/web/.storybook/utils/with-bootstrap-switcher.tsx

@@ -10,11 +10,11 @@ export const bsVersionDecorator: Meta = {
       control: { type: 'inline-radio' },
       options: ['3', '5'],
       table: {
-        defaultValue: { summary: '3' },
+        defaultValue: { summary: '5' },
       },
     },
   },
   args: {
-    [bootstrapVersionArg]: '3',
+    [bootstrapVersionArg]: '5',
   },
 }

+ 1 - 0
services/web/cypress/support/component.ts

@@ -5,6 +5,7 @@ import './shared/commands'
 import './shared/exceptions'
 import './ct/commands'
 import './ct/codemirror'
+import '../../test/frontend/helpers/bootstrap-5'
 
 beforeEach(function () {
   resetMeta()

+ 1 - 0
services/web/cypress/support/ct/window.ts

@@ -10,6 +10,7 @@ export function resetMeta() {
     hasLinkedProjectOutputFileFeature: true,
     hasLinkUrlFeature: true,
   })
+  window.metaAttributesCache.set('ol-bootstrapVersion', 5)
 }
 
 // Populate meta for top-level access in modules on import

+ 2 - 7
services/web/cypress/support/shared/commands/compile.ts

@@ -84,11 +84,7 @@ export const waitForCompile = ({ prefix = 'compile', pdf = false } = {}) => {
 }
 
 export const interceptDeferredCompile = (beforeResponse?: () => void) => {
-  let resolveDeferredCompile: (value?: unknown) => void
-
-  const promise = new Promise(resolve => {
-    resolveDeferredCompile = resolve
-  })
+  const { promise, resolve } = Promise.withResolvers<void>()
 
   cy.intercept(
     { method: 'POST', url: '/project/*/compile*', times: 1 },
@@ -148,6 +144,5 @@ export const interceptDeferredCompile = (beforeResponse?: () => void) => {
     { fixture: 'build/output.blg' }
   ).as(`compile-blg`)
 
-  // @ts-ignore
-  return cy.wrap(resolveDeferredCompile)
+  return cy.wrap(resolve)
 }

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

@@ -342,7 +342,6 @@
   "create_project_in_github": "",
   "created": "",
   "created_at": "",
-  "creating": "",
   "current_file": "",
   "current_password": "",
   "currently_seeing_only_24_hrs_history": "",
@@ -699,12 +698,10 @@
   "hide_outline": "",
   "history": "",
   "history_add_label": "",
-  "history_adding_label": "",
   "history_are_you_sure_delete_label": "",
   "history_compare_from_this_version": "",
   "history_compare_up_to_this_version": "",
   "history_delete_label": "",
-  "history_deleting_label": "",
   "history_download_this_version": "",
   "history_entry_origin_dropbox": "",
   "history_entry_origin_git": "",
@@ -1384,7 +1381,6 @@
   "restore_file_version": "",
   "restore_project_to_this_version": "",
   "restore_this_version": "",
-  "restoring": "",
   "resync_completed": "",
   "resync_message": "",
   "resync_project_history": "",

+ 3 - 13
services/web/frontend/js/features/chat/components/chat-pane.tsx

@@ -4,22 +4,17 @@ import { useTranslation } from 'react-i18next'
 import MessageInput from './message-input'
 import InfiniteScroll from './infinite-scroll'
 import ChatFallbackError from './chat-fallback-error'
-import Icon from '../../../shared/components/icon'
 import { useLayoutContext } from '../../../shared/context/layout-context'
 import { useUserContext } from '../../../shared/context/user-context'
 import withErrorBoundary from '../../../infrastructure/error-boundary'
 import { FetchError } from '../../../infrastructure/fetch-json'
 import { useChatContext } from '../context/chat-context'
 import { FullSizeLoadingSpinner } from '../../../shared/components/loading-spinner'
-import { bsVersion } from '@/features/utils/bootstrap-5'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 const MessageList = lazy(() => import('./message-list'))
 
-const Loading = () => (
-  <FullSizeLoadingSpinner delay={500} className={bsVersion({ bs5: 'pt-4' })} />
-)
+const Loading = () => <FullSizeLoadingSpinner delay={500} className="pt-4" />
 
 const ChatPane = React.memo(function ChatPane() {
   const { t } = useTranslation()
@@ -86,9 +81,7 @@ const ChatPane = React.memo(function ChatPane() {
         itemCount={messageContentCount}
       >
         <div>
-          <h2 className={bsVersion({ bs3: 'sr-only', bs5: 'visually-hidden' })}>
-            {t('chat')}
-          </h2>
+          <h2 className="visually-hidden">{t('chat')}</h2>
           <Suspense fallback={<Loading />}>
             {status === 'pending' && <Loading />}
             {shouldDisplayPlaceholder && <Placeholder />}
@@ -115,10 +108,7 @@ function Placeholder() {
       <div className="first-message text-center">
         {t('send_first_message')}
         <br />
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="arrow-down" />}
-          bs5={<MaterialIcon type="arrow_downward" />}
-        />
+        <MaterialIcon type="arrow_downward" />
       </div>
     </>
   )

+ 1 - 5
services/web/frontend/js/features/chat/components/message-input.tsx

@@ -1,5 +1,4 @@
 import { useTranslation } from 'react-i18next'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 type MessageInputProps = {
   resetUnreadMessages: () => void
@@ -27,10 +26,7 @@ function MessageInput({ resetUnreadMessages, sendMessage }: MessageInputProps) {
 
   return (
     <form className="new-message">
-      <label
-        htmlFor="chat-input"
-        className={bsVersion({ bs3: 'sr-only', bs5: 'visually-hidden' })}
-      >
+      <label htmlFor="chat-input" className="visually-hidden">
         {t('your_message_to_collaborators')}
       </label>
       <textarea

+ 13 - 40
services/web/frontend/js/features/clone-project-modal/components/clone-project-tag.tsx

@@ -1,53 +1,26 @@
 import { FC } from 'react'
 import { Tag as TagType } from '../../../../../app/src/Features/Tags/types'
 import { getTagColor } from '@/features/project-list/util/tag'
-import Icon from '@/shared/components/icon'
-import { useTranslation } from 'react-i18next'
 import Tag from '@/features/ui/components/bootstrap-5/tag'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 export const CloneProjectTag: FC<{
   tag: TagType
   removeTag: (tag: TagType) => void
 }> = ({ tag, removeTag }) => {
-  const { t } = useTranslation()
-
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <div className="tag-label" role="option" aria-selected>
-          <span className="label label-default tag-label-name">
-            <span style={{ color: getTagColor(tag) }}>
-              <Icon type="circle" aria-hidden />
-            </span>{' '}
-            {tag.name}
-          </span>
-          <button
-            type="button"
-            className="label label-default tag-label-remove"
-            onClick={() => removeTag(tag)}
-            aria-label={t('remove_tag', { tagName: tag.name })}
-          >
-            <span aria-hidden="true">×</span>
-          </button>
-        </div>
-      }
-      bs5={
-        <Tag
-          prepend={
-            <i
-              className="badge-tag-circle"
-              style={{ backgroundColor: getTagColor(tag) }}
-            />
-          }
-          closeBtnProps={{
-            onClick: () => removeTag(tag),
-          }}
-          className="ms-2 mb-2"
-        >
-          {tag.name}
-        </Tag>
+    <Tag
+      prepend={
+        <i
+          className="badge-tag-circle"
+          style={{ backgroundColor: getTagColor(tag) }}
+        />
       }
-    />
+      closeBtnProps={{
+        onClick: () => removeTag(tag),
+      }}
+      className="ms-2 mb-2"
+    >
+      {tag.name}
+    </Tag>
   )
 }

+ 1 - 8
services/web/frontend/js/features/dictionary/components/dictionary-modal-content.tsx

@@ -13,7 +13,6 @@ import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLNotification from '@/features/ui/components/ol/ol-notification'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLIconButton from '@/features/ui/components/ol/ol-icon-button'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import { learnedWords as initialLearnedWords } from '@/features/source-editor/extensions/spelling/learned-words'
 
 type DictionaryModalContentProps = {
@@ -79,13 +78,7 @@ export default function DictionaryModalContent({
                     variant="danger"
                     size="sm"
                     onClick={() => handleRemove(learnedWord)}
-                    bs3Props={{ bsSize: 'xsmall' }}
-                    icon={
-                      bsVersion({
-                        bs5: 'delete',
-                        bs3: 'trash-o',
-                      }) as string
-                    }
+                    icon="delete"
                     accessibilityLabel={t('edit_dictionary_remove')}
                   />
                 </OLTooltip>

+ 2 - 10
services/web/frontend/js/features/editor-left-menu/components/download-pdf.tsx

@@ -1,10 +1,8 @@
 import { useTranslation } from 'react-i18next'
 import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
 import { useProjectContext } from '../../../shared/context/project-context'
-import Icon from '../../../shared/components/icon'
 import * as eventTracking from '../../../infrastructure/event-tracking'
 import { isSmallDevice } from '../../../infrastructure/event-tracking'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 
@@ -29,10 +27,7 @@ export default function DownloadPDF() {
         rel="noreferrer"
         onClick={sendDownloadEvent}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="file-pdf-o" modifier="2x" />}
-          bs5={<MaterialIcon type="picture_as_pdf" size="2x" />}
-        />
+        <MaterialIcon type="picture_as_pdf" size="2x" />
         <br />
         PDF
       </a>
@@ -45,10 +40,7 @@ export default function DownloadPDF() {
         overlayProps={{ placement: 'bottom' }}
       >
         <div className="link-disabled">
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="file-pdf-o" modifier="2x" />}
-            bs5={<MaterialIcon type="picture_as_pdf" size="2x" />}
-          />
+          <MaterialIcon type="picture_as_pdf" size="2x" />
           <br />
           PDF
         </div>

+ 1 - 6
services/web/frontend/js/features/editor-left-menu/components/download-source.tsx

@@ -1,9 +1,7 @@
 import { useTranslation } from 'react-i18next'
 import { useProjectContext } from '../../../shared/context/project-context'
-import Icon from '../../../shared/components/icon'
 import * as eventTracking from '../../../infrastructure/event-tracking'
 import { isSmallDevice } from '../../../infrastructure/event-tracking'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 export default function DownloadSource() {
@@ -25,10 +23,7 @@ export default function DownloadSource() {
       rel="noreferrer"
       onClick={sendDownloadEvent}
     >
-      <BootstrapVersionSwitcher
-        bs3={<Icon type="file-archive-o" modifier="2x" />}
-        bs5={<MaterialIcon type="folder_zip" size="2x" />}
-      />
+      <MaterialIcon type="folder_zip" size="2x" />
       <br />
       {t('source')}
     </a>

+ 18 - 46
services/web/frontend/js/features/editor-left-menu/components/editor-left-menu.tsx

@@ -1,11 +1,8 @@
 import { useLayoutContext } from '../../../shared/context/layout-context'
 import LeftMenuMask from './left-menu-mask'
-import AccessibleModal from '../../../shared/components/accessible-modal'
-import { Modal } from 'react-bootstrap'
 import classNames from 'classnames'
 import { lazy, memo, Suspense } from 'react'
 import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { Offcanvas } from 'react-bootstrap-5'
 import { EditorLeftMenuProvider } from './editor-left-menu-context'
 import withErrorBoundary from '@/infrastructure/error-boundary'
@@ -34,49 +31,24 @@ function EditorLeftMenu() {
   }
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <EditorLeftMenuProvider>
-          <AccessibleModal
-            backdropClassName="left-menu-modal-backdrop"
-            keyboard
-            onHide={closeLeftMenu}
-            id="left-menu-modal"
-            show={leftMenuShown}
-          >
-            <Modal.Body
-              className={classNames('full-size', { shown: leftMenuShown })}
-              id="left-menu"
-            >
-              <Suspense fallback={<FullSizeLoadingSpinner delay={500} />}>
-                <EditorLeftMenuBody />
-              </Suspense>
-            </Modal.Body>
-          </AccessibleModal>
-          {leftMenuShown && <LeftMenuMask />}
-        </EditorLeftMenuProvider>
-      }
-      bs5={
-        <EditorLeftMenuProvider>
-          <Offcanvas
-            show={leftMenuShown}
-            onHide={closeLeftMenu}
-            backdropClassName="left-menu-modal-backdrop"
-            id="left-menu-offcanvas"
-          >
-            <Offcanvas.Body
-              className={classNames('full-size', 'left-menu', {
-                shown: leftMenuShown,
-              })}
-              id="left-menu"
-            >
-              <LazyEditorLeftMenuWithErrorBoundary />
-            </Offcanvas.Body>
-          </Offcanvas>
-          {leftMenuShown && <LeftMenuMask />}
-        </EditorLeftMenuProvider>
-      }
-    />
+    <EditorLeftMenuProvider>
+      <Offcanvas
+        show={leftMenuShown}
+        onHide={closeLeftMenu}
+        backdropClassName="left-menu-modal-backdrop"
+        id="left-menu-offcanvas"
+      >
+        <Offcanvas.Body
+          className={classNames('full-size', 'left-menu', {
+            shown: leftMenuShown,
+          })}
+          id="left-menu"
+        >
+          <LazyEditorLeftMenuWithErrorBoundary />
+        </Offcanvas.Body>
+      </Offcanvas>
+      {leftMenuShown && <LeftMenuMask />}
+    </EditorLeftMenuProvider>
   )
 }
 

+ 1 - 8
services/web/frontend/js/features/editor-left-menu/components/left-menu-button.tsx

@@ -1,6 +1,4 @@
 import { PropsWithChildren } from 'react'
-import Icon from '../../../shared/components/icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 type Props = {
@@ -26,12 +24,7 @@ function LeftMenuButtonIcon({
   if (svgIcon) {
     return <div className="material-symbols">{svgIcon}</div>
   } else if (icon) {
-    return (
-      <BootstrapVersionSwitcher
-        bs3={<Icon type={icon.type} fw={icon.fw ?? false} />}
-        bs5={<MaterialIcon type={icon.type} />}
-      />
-    )
+    return <MaterialIcon type={icon.type} />
   } else return null
 }
 

+ 0 - 1
services/web/frontend/js/features/editor-left-menu/components/settings/settings-dictionary.tsx

@@ -17,7 +17,6 @@ export default function SettingsDictionary() {
         variant="secondary"
         size="sm"
         onClick={() => setShowModal(true)}
-        bs3Props={{ bsSize: 'xsmall' }}
       >
         {t('edit')}
       </OLButton>

+ 8 - 18
services/web/frontend/js/features/editor-left-menu/components/settings/settings-menu-select.tsx

@@ -1,4 +1,3 @@
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
 import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
 import OLFormSelect from '@/features/ui/components/ol/ol-form-select'
@@ -81,23 +80,14 @@ export default function SettingsMenuSelect<T extends PossibleValue = string>({
     >
       <OLFormLabel>{label}</OLFormLabel>
       {loading ? (
-        <BootstrapVersionSwitcher
-          bs3={
-            <p className="loading pull-right">
-              <i className="fa fa-fw fa-spin fa-refresh" />
-            </p>
-          }
-          bs5={
-            <p className="mb-0">
-              <Spinner
-                animation="border"
-                aria-hidden="true"
-                size="sm"
-                role="status"
-              />
-            </p>
-          }
-        />
+        <p className="mb-0">
+          <Spinner
+            animation="border"
+            aria-hidden="true"
+            size="sm"
+            role="status"
+          />
+        </p>
       ) : (
         <OLFormSelect
           size="sm"

+ 4 - 17
services/web/frontend/js/features/editor-navigation-toolbar/components/back-to-projects-button.tsx

@@ -1,8 +1,6 @@
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
 import * as eventTracking from '../../../infrastructure/event-tracking'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 function BackToProjectsButton() {
@@ -23,21 +21,10 @@ function BackToProjectsButton() {
             eventTracking.sendMB('navigation-clicked-home')
           }}
         >
-          <BootstrapVersionSwitcher
-            bs3={
-              <Icon
-                type="home"
-                fw
-                accessibilityLabel={t('back_to_your_projects')}
-              />
-            }
-            bs5={
-              <MaterialIcon
-                type="home"
-                className="align-text-bottom"
-                accessibilityLabel={t('back_to_your_projects')}
-              />
-            }
+          <MaterialIcon
+            type="home"
+            className="align-text-bottom"
+            accessibilityLabel={t('back_to_your_projects')}
           />
         </a>
       </div>

+ 5 - 18
services/web/frontend/js/features/editor-navigation-toolbar/components/chat-toggle-button.jsx

@@ -1,8 +1,6 @@
 import PropTypes from 'prop-types'
 import classNames from 'classnames'
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import OLBadge from '@/features/ui/components/ol/ol-badge'
 
@@ -15,22 +13,11 @@ function ChatToggleButton({ chatIsOpen, unreadMessageCount, onClick }) {
   return (
     <div className="toolbar-item">
       <button type="button" className={classes} onClick={onClick}>
-        <BootstrapVersionSwitcher
-          bs3={
-            <Icon
-              type="comment"
-              fw
-              className={classNames({ bounce: hasUnreadMessages })}
-            />
-          }
-          bs5={
-            <MaterialIcon
-              type="chat"
-              className={classNames('align-middle', {
-                bounce: hasUnreadMessages,
-              })}
-            />
-          }
+        <MaterialIcon
+          type="chat"
+          className={classNames('align-middle', {
+            bounce: hasUnreadMessages,
+          })}
         />
         {hasUnreadMessages && <OLBadge bg="info">{unreadMessageCount}</OLBadge>}
         <p className="toolbar-label">{t('chat')}</p>

+ 1 - 6
services/web/frontend/js/features/editor-navigation-toolbar/components/history-toggle-button.jsx

@@ -1,8 +1,6 @@
 import PropTypes from 'prop-types'
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function HistoryToggleButton({ onClick }) {
   const { t } = useTranslation()
@@ -10,10 +8,7 @@ function HistoryToggleButton({ onClick }) {
   return (
     <div className="toolbar-item">
       <button type="button" className="btn btn-full-height" onClick={onClick}>
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="history" fw />}
-          bs5={<MaterialIcon type="history" className="align-middle" />}
-        />
+        <MaterialIcon type="history" className="align-middle" />
         <p className="toolbar-label">{t('history')}</p>
       </button>
     </div>

+ 99 - 283
services/web/frontend/js/features/editor-navigation-toolbar/components/layout-dropdown-button.tsx

@@ -1,9 +1,4 @@
-import { memo, ReactNode, useCallback, forwardRef } from 'react'
-import {
-  Dropdown as BS3Dropdown,
-  MenuItem,
-  MenuItemProps,
-} from 'react-bootstrap'
+import { memo, useCallback, forwardRef } from 'react'
 import { Spinner } from 'react-bootstrap-5'
 import {
   Dropdown,
@@ -13,10 +8,6 @@ import {
   DropdownToggleCustom,
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
 import { Trans, useTranslation } from 'react-i18next'
-import Tooltip from '../../../shared/components/tooltip'
-import Icon from '../../../shared/components/icon'
-import IconChecked from '../../../shared/components/icon-checked'
-import ControlledDropdown from '../../../shared/components/controlled-dropdown'
 import {
   IdeLayout,
   IdeView,
@@ -25,38 +16,9 @@ import {
 import * as eventTracking from '../../../infrastructure/event-tracking'
 import useEventListener from '../../../shared/hooks/use-event-listener'
 import { DetachRole } from '@/shared/context/detach-context'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 
-function IconPlaceholder() {
-  return <Icon type="" fw />
-}
-
-function IconRefresh() {
-  return <Icon type="refresh" fw spin />
-}
-
-function IconLayout() {
-  return <Icon type="columns" fw />
-}
-
-function IconSplit() {
-  return <Icon type="columns" fw />
-}
-
-function IconDetach() {
-  return <Icon type="window-restore" fw />
-}
-
-function IconEditorOnly() {
-  return <Icon type="code" fw />
-}
-
-function IconPdfOnly() {
-  return <Icon type="file-pdf-o" fw />
-}
-
 const isActiveDropdownItem = ({
   iconFor,
   pdfLayout,
@@ -85,33 +47,6 @@ const isActiveDropdownItem = ({
   return false
 }
 
-function IconCheckmark(props: Parameters<typeof isActiveDropdownItem>[0]) {
-  return isActiveDropdownItem(props) ? <IconChecked /> : <IconPlaceholder />
-}
-
-function LayoutMenuItem({
-  checkmark,
-  icon,
-  text,
-  ...props
-}: {
-  checkmark: ReactNode
-  icon: ReactNode
-  text: string | ReactNode
-} & MenuItemProps) {
-  return (
-    <MenuItem {...props}>
-      <div className="layout-menu-item">
-        <div className="layout-menu-item-start">
-          <div>{checkmark}</div>
-          <div>{icon}</div>
-          <div>{text}</div>
-        </div>
-      </div>
-    </MenuItem>
-  )
-}
-
 function EnhancedDropdownItem({
   active,
   ...props
@@ -141,25 +76,6 @@ const LayoutDropdownToggleButton = forwardRef<
 })
 LayoutDropdownToggleButton.displayName = 'LayoutDropdownToggleButton'
 
-function BS3DetachDisabled() {
-  const { t } = useTranslation()
-
-  return (
-    <Tooltip
-      id="detach-disabled"
-      description={t('your_browser_does_not_support_this_feature')}
-      overlayProps={{ placement: 'left' }}
-    >
-      <LayoutMenuItem
-        disabled
-        checkmark={<IconPlaceholder />}
-        icon={<IconDetach />}
-        text={t('pdf_in_separate_tab')}
-      />
-    </Tooltip>
-  )
-}
-
 function BS5DetachDisabled() {
   const { t } = useTranslation()
 
@@ -260,208 +176,108 @@ export const LayoutDropdownButtonUi = ({
           {t('layout_processing')}
         </div>
       )}
-      <BootstrapVersionSwitcher
-        bs3={
-          <ControlledDropdown
-            id="layout-dropdown"
-            onMainButtonClick={() => {
-              eventTracking.sendMB('navigation-clicked-layout')
-            }}
-            className="toolbar-item layout-dropdown"
-            pullRight
+      <Dropdown className="toolbar-item layout-dropdown" align="end">
+        <DropdownToggle
+          id="layout-dropdown-btn"
+          className="btn-full-height"
+          as={LayoutDropdownToggleButton}
+        >
+          {processing ? (
+            <Spinner
+              animation="border"
+              aria-hidden="true"
+              size="sm"
+              role="status"
+            />
+          ) : (
+            <MaterialIcon type="dock_to_right" className="align-middle" />
+          )}
+          <span className="toolbar-label">{t('layout')}</span>
+        </DropdownToggle>
+        <DropdownMenu>
+          <EnhancedDropdownItem
+            onClick={() => handleChangeLayout('sideBySide')}
+            active={isActiveDropdownItem({
+              iconFor: 'sideBySide',
+              pdfLayout,
+              view,
+              detachRole,
+            })}
+            leadingIcon="dock_to_right"
           >
-            {/* bsStyle is required for Dropdown.Toggle, but we will override style */}
-            <BS3Dropdown.Toggle className="btn-full-height" bsStyle="link">
-              {processing ? <IconRefresh /> : <IconLayout />}
-              <span className="toolbar-label">{t('layout')}</span>
-            </BS3Dropdown.Toggle>
-            <BS3Dropdown.Menu className="layout-dropdown-list">
-              <LayoutMenuItem
-                onSelect={() => handleChangeLayout('sideBySide')}
-                checkmark={
-                  <IconCheckmark
-                    iconFor="sideBySide"
-                    pdfLayout={pdfLayout}
-                    view={view}
-                    detachRole={detachRole}
-                  />
-                }
-                icon={<IconSplit />}
-                text={t('editor_and_pdf')}
-              />
-
-              <LayoutMenuItem
-                onSelect={() => handleChangeLayout('flat', 'editor')}
-                checkmark={
-                  <IconCheckmark
-                    iconFor="editorOnly"
-                    pdfLayout={pdfLayout}
-                    view={view}
-                    detachRole={detachRole}
-                  />
-                }
-                icon={<IconEditorOnly />}
-                text={
-                  <Trans
-                    i18nKey="editor_only_hide_pdf"
-                    components={[
-                      <span key="editor_only_hide_pdf" className="subdued" />,
-                    ]}
-                  />
-                }
+            {t('editor_and_pdf')}
+          </EnhancedDropdownItem>
+
+          <EnhancedDropdownItem
+            onClick={() => handleChangeLayout('flat', 'editor')}
+            active={isActiveDropdownItem({
+              iconFor: 'editorOnly',
+              pdfLayout,
+              view,
+              detachRole,
+            })}
+            leadingIcon="code"
+          >
+            <div className="d-flex flex-column">
+              <Trans
+                i18nKey="editor_only_hide_pdf"
+                components={[
+                  <span key="editor_only_hide_pdf" className="subdued" />,
+                ]}
               />
-
-              <LayoutMenuItem
-                onSelect={() => handleChangeLayout('flat', 'pdf')}
-                checkmark={
-                  <IconCheckmark
-                    iconFor="pdfOnly"
-                    pdfLayout={pdfLayout}
-                    view={view}
-                    detachRole={detachRole}
-                  />
-                }
-                icon={<IconPdfOnly />}
-                text={
-                  <Trans
-                    i18nKey="pdf_only_hide_editor"
-                    components={[
-                      <span key="pdf_only_hide_editor" className="subdued" />,
-                    ]}
-                  />
-                }
+            </div>
+          </EnhancedDropdownItem>
+
+          <EnhancedDropdownItem
+            onClick={() => handleChangeLayout('flat', 'pdf')}
+            active={isActiveDropdownItem({
+              iconFor: 'pdfOnly',
+              pdfLayout,
+              view,
+              detachRole,
+            })}
+            leadingIcon="picture_as_pdf"
+          >
+            <div className="d-flex flex-column">
+              <Trans
+                i18nKey="pdf_only_hide_editor"
+                components={[
+                  <span key="pdf_only_hide_editor" className="subdued" />,
+                ]}
               />
-
-              {detachable ? (
-                <LayoutMenuItem
-                  onSelect={() => handleDetach()}
-                  checkmark={
-                    detachRole === 'detacher' ? (
-                      detachIsLinked ? (
-                        <IconChecked />
-                      ) : (
-                        <IconRefresh />
-                      )
-                    ) : (
-                      <IconPlaceholder />
-                    )
-                  }
-                  icon={<IconDetach />}
-                  text={t('pdf_in_separate_tab')}
-                />
-              ) : (
-                <BS3DetachDisabled />
-              )}
-            </BS3Dropdown.Menu>
-          </ControlledDropdown>
-        }
-        bs5={
-          <Dropdown className="toolbar-item layout-dropdown" align="end">
-            <DropdownToggle
-              id="layout-dropdown-btn"
-              className="btn-full-height"
-              as={LayoutDropdownToggleButton}
+            </div>
+          </EnhancedDropdownItem>
+
+          {detachable ? (
+            <EnhancedDropdownItem
+              onClick={() => handleDetach()}
+              active={detachRole === 'detacher' && detachIsLinked}
+              trailingIcon={
+                detachRole === 'detacher' ? (
+                  detachIsLinked ? (
+                    'check'
+                  ) : (
+                    <span className="spinner-container">
+                      <Spinner
+                        animation="border"
+                        aria-hidden="true"
+                        size="sm"
+                        role="status"
+                      />
+                      <span className="visually-hidden">{t('loading')}</span>
+                    </span>
+                  )
+                ) : null
+              }
+              leadingIcon="select_window"
             >
-              {processing ? (
-                <Spinner
-                  animation="border"
-                  aria-hidden="true"
-                  size="sm"
-                  role="status"
-                />
-              ) : (
-                <MaterialIcon type="dock_to_right" className="align-middle" />
-              )}
-              <span className="toolbar-label">{t('layout')}</span>
-            </DropdownToggle>
-            <DropdownMenu>
-              <EnhancedDropdownItem
-                onClick={() => handleChangeLayout('sideBySide')}
-                active={isActiveDropdownItem({
-                  iconFor: 'sideBySide',
-                  pdfLayout,
-                  view,
-                  detachRole,
-                })}
-                leadingIcon="dock_to_right"
-              >
-                {t('editor_and_pdf')}
-              </EnhancedDropdownItem>
-
-              <EnhancedDropdownItem
-                onClick={() => handleChangeLayout('flat', 'editor')}
-                active={isActiveDropdownItem({
-                  iconFor: 'editorOnly',
-                  pdfLayout,
-                  view,
-                  detachRole,
-                })}
-                leadingIcon="code"
-              >
-                <div className="d-flex flex-column">
-                  <Trans
-                    i18nKey="editor_only_hide_pdf"
-                    components={[
-                      <span key="editor_only_hide_pdf" className="subdued" />,
-                    ]}
-                  />
-                </div>
-              </EnhancedDropdownItem>
-
-              <EnhancedDropdownItem
-                onClick={() => handleChangeLayout('flat', 'pdf')}
-                active={isActiveDropdownItem({
-                  iconFor: 'pdfOnly',
-                  pdfLayout,
-                  view,
-                  detachRole,
-                })}
-                leadingIcon="picture_as_pdf"
-              >
-                <div className="d-flex flex-column">
-                  <Trans
-                    i18nKey="pdf_only_hide_editor"
-                    components={[
-                      <span key="pdf_only_hide_editor" className="subdued" />,
-                    ]}
-                  />
-                </div>
-              </EnhancedDropdownItem>
-
-              {detachable ? (
-                <EnhancedDropdownItem
-                  onClick={() => handleDetach()}
-                  active={detachRole === 'detacher' && detachIsLinked}
-                  trailingIcon={
-                    detachRole === 'detacher' ? (
-                      detachIsLinked ? (
-                        'check'
-                      ) : (
-                        <span className="spinner-container">
-                          <Spinner
-                            animation="border"
-                            aria-hidden="true"
-                            size="sm"
-                            role="status"
-                          />
-                          <span className="visually-hidden">
-                            {t('loading')}
-                          </span>
-                        </span>
-                      )
-                    ) : null
-                  }
-                  leadingIcon="select_window"
-                >
-                  {t('pdf_in_separate_tab')}
-                </EnhancedDropdownItem>
-              ) : (
-                <BS5DetachDisabled />
-              )}
-            </DropdownMenu>
-          </Dropdown>
-        }
-      />
+              {t('pdf_in_separate_tab')}
+            </EnhancedDropdownItem>
+          ) : (
+            <BS5DetachDisabled />
+          )}
+        </DropdownMenu>
+      </Dropdown>
     </>
   )
 }

+ 1 - 11
services/web/frontend/js/features/editor-navigation-toolbar/components/menu-button.jsx

@@ -1,8 +1,6 @@
 import PropTypes from 'prop-types'
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function MenuButton({ onClick }) {
   const { t } = useTranslation()
@@ -10,15 +8,7 @@ function MenuButton({ onClick }) {
   return (
     <div className="toolbar-item">
       <button type="button" className="btn btn-full-height" onClick={onClick}>
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="bars" fw className="editor-menu-icon" />}
-          bs5={
-            <MaterialIcon
-              type="menu"
-              className="editor-menu-icon align-middle"
-            />
-          }
-        />
+        <MaterialIcon type="menu" className="editor-menu-icon align-middle" />
         <p className="toolbar-label">{t('menu')}</p>
       </button>
     </div>

+ 23 - 59
services/web/frontend/js/features/editor-navigation-toolbar/components/online-users-widget.jsx

@@ -1,7 +1,6 @@
 import React from 'react'
 import PropTypes from 'prop-types'
 import { useTranslation } from 'react-i18next'
-import { Dropdown as BS3Dropdown, MenuItem } from 'react-bootstrap'
 import {
   Dropdown,
   DropdownHeader,
@@ -9,11 +8,8 @@ import {
   DropdownMenu,
   DropdownToggle,
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
-import Icon from '../../../shared/components/icon'
 import { getBackgroundColorForUserId } from '@/shared/utils/colors'
-import ControlledDropdown from '../../../shared/components/controlled-dropdown'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 function OnlineUsersWidget({ onlineUsers, goToUser }) {
@@ -23,57 +19,28 @@ function OnlineUsersWidget({ onlineUsers, goToUser }) {
 
   if (shouldDisplayDropdown) {
     return (
-      <BootstrapVersionSwitcher
-        bs3={
-          <ControlledDropdown
-            id="online-users"
-            className="online-users"
-            pullRight
-          >
-            <DropDownToggleButton
-              bsRole="toggle"
-              onlineUserCount={onlineUsers.length}
-            />
-            <BS3Dropdown.Menu>
-              <MenuItem header>{t('connected_users')}</MenuItem>
-              {onlineUsers.map((user, index) => (
-                <MenuItem
-                  as="button"
-                  key={`${user.user_id}_${index}`}
-                  eventKey={user}
-                  onSelect={goToUser}
-                >
-                  <UserIcon user={user} showName />
-                </MenuItem>
-              ))}
-            </BS3Dropdown.Menu>
-          </ControlledDropdown>
-        }
-        bs5={
-          <Dropdown id="online-users" className="online-users" align="end">
-            <DropdownToggle
-              as={DropDownToggleButton}
-              onlineUserCount={onlineUsers.length}
-            />
-            <DropdownMenu>
-              <DropdownHeader aria-hidden="true">
-                {t('connected_users')}
-              </DropdownHeader>
-              {onlineUsers.map((user, index) => (
-                <li role="none" key={`${user.user_id}_${index}`}>
-                  <DropdownItem
-                    as="button"
-                    tabIndex={-1}
-                    onClick={() => goToUser(user)}
-                  >
-                    <UserIcon user={user} showName />
-                  </DropdownItem>
-                </li>
-              ))}
-            </DropdownMenu>
-          </Dropdown>
-        }
-      />
+      <Dropdown id="online-users" className="online-users" align="end">
+        <DropdownToggle
+          as={DropDownToggleButton}
+          onlineUserCount={onlineUsers.length}
+        />
+        <DropdownMenu>
+          <DropdownHeader aria-hidden="true">
+            {t('connected_users')}
+          </DropdownHeader>
+          {onlineUsers.map((user, index) => (
+            <li role="none" key={`${user.user_id}_${index}`}>
+              <DropdownItem
+                as="button"
+                tabIndex={-1}
+                onClick={() => goToUser(user)}
+              >
+                <UserIcon user={user} showName />
+              </DropdownItem>
+            </li>
+          ))}
+        </DropdownMenu>
+      </Dropdown>
     )
   } else {
     return (
@@ -150,10 +117,7 @@ const DropDownToggleButton = React.forwardRef((props, ref) => {
         ref={ref}
       >
         <strong>{props.onlineUserCount}</strong>&nbsp;
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="users" fw />}
-          bs5={<MaterialIcon type="groups" />}
-        />
+        <MaterialIcon type="groups" />
       </button>
     </OLTooltip>
   )

+ 1 - 6
services/web/frontend/js/features/editor-navigation-toolbar/components/project-name-editable-label.tsx

@@ -1,11 +1,9 @@
 import { useEffect, useState, useRef } from 'react'
 import { useTranslation } from 'react-i18next'
 import classNames from 'classnames'
-import Icon from '../../../shared/components/icon'
 import OLFormControl from '@/features/ui/components/ol/ol-form-control'
 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'
 
 type ProjectNameEditableLabelProps = {
   projectName: string
@@ -90,10 +88,7 @@ function ProjectNameEditableLabel({
         >
           {/* eslint-disable-next-line jsx-a11y/anchor-is-valid, jsx-a11y/click-events-have-key-events, jsx-a11y/interactive-supports-focus */}
           <a className="rename" role="button" onClick={startRenaming}>
-            <BootstrapVersionSwitcher
-              bs3={<Icon type="pencil" fw />}
-              bs5={<MaterialIcon type="edit" className="align-text-bottom" />}
-            />
+            <MaterialIcon type="edit" className="align-text-bottom" />
           </a>
         </OLTooltip>
       )}

+ 1 - 6
services/web/frontend/js/features/editor-navigation-toolbar/components/share-project-button.jsx

@@ -1,8 +1,6 @@
 import PropTypes from 'prop-types'
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function ShareProjectButton({ onClick }) {
   const { t } = useTranslation()
@@ -10,10 +8,7 @@ function ShareProjectButton({ onClick }) {
   return (
     <div className="toolbar-item">
       <button type="button" className="btn btn-full-height" onClick={onClick}>
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="group" fw />}
-          bs5={<MaterialIcon type="group_add" className="align-middle" />}
-        />
+        <MaterialIcon type="group_add" className="align-middle" />
         <p className="toolbar-label">{t('share')}</p>
       </button>
     </div>

+ 6 - 17
services/web/frontend/js/features/editor-navigation-toolbar/components/toolbar-header.jsx

@@ -16,7 +16,6 @@ import importOverleafModules from '../../../../macros/import-overleaf-module.mac
 import BackToEditorButton from './back-to-editor-button'
 import getMeta from '@/utils/meta'
 import { isSplitTestEnabled } from '@/utils/splitTestUtils'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 const [publishModalModules] = importOverleafModules('publishModal')
 const PublishButton = publishModalModules?.import.default
@@ -76,14 +75,9 @@ const ToolbarHeader = React.memo(function ToolbarHeader({
           )}
       </div>
       {getMeta('ol-showUpgradePrompt') && (
-        <BootstrapVersionSwitcher
-          bs3={<UpgradePrompt />}
-          bs5={
-            <div className="d-flex align-items-center">
-              <UpgradePrompt />
-            </div>
-          }
-        />
+        <div className="d-flex align-items-center">
+          <UpgradePrompt />
+        </div>
       )}
       <ProjectNameEditableLabel
         className="toolbar-center"
@@ -96,14 +90,9 @@ const ToolbarHeader = React.memo(function ToolbarHeader({
         <OnlineUsersWidget onlineUsers={onlineUsers} goToUser={goToUser} />
 
         {historyIsOpen ? (
-          <BootstrapVersionSwitcher
-            bs3={<BackToEditorButton onClick={toggleHistoryOpen} />}
-            bs5={
-              <div className="d-flex align-items-center">
-                <BackToEditorButton onClick={toggleHistoryOpen} />
-              </div>
-            }
-          />
+          <div className="d-flex align-items-center">
+            <BackToEditorButton onClick={toggleHistoryOpen} />
+          </div>
         ) : (
           <>
             {trackChangesVisible && (

+ 1 - 5
services/web/frontend/js/features/editor-navigation-toolbar/components/track-changes-toggle-button.jsx

@@ -1,7 +1,6 @@
 import PropTypes from 'prop-types'
 import classNames from 'classnames'
 import { useTranslation } from 'react-i18next'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 function TrackChangesToggleButton({
@@ -23,10 +22,7 @@ function TrackChangesToggleButton({
         className={classes}
         onMouseDown={onMouseDown}
       >
-        <BootstrapVersionSwitcher
-          bs3={<i className="review-icon" />}
-          bs5={<MaterialIcon type="rate_review" className="align-middle" />}
-        />
+        <MaterialIcon type="rate_review" className="align-middle" />
         <p className="toolbar-label">{t('review')}</p>
       </button>
     </div>

+ 1 - 6
services/web/frontend/js/features/editor-navigation-toolbar/components/upgrade-prompt.jsx

@@ -1,8 +1,6 @@
 import { useTranslation } from 'react-i18next'
 import * as eventTracking from '../../../infrastructure/event-tracking'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import { bsVersion } from '@/features/utils/bootstrap-5'
-import classnames from 'classnames'
 
 function UpgradePrompt() {
   const { t } = useTranslation()
@@ -16,10 +14,7 @@ function UpgradePrompt() {
     <OLButton
       variant="primary"
       size="sm"
-      className={classnames(
-        'toolbar-header-upgrade-prompt',
-        bsVersion({ bs3: 'btn-xs' })
-      )}
+      className="toolbar-header-upgrade-prompt"
       href="/user/subscription/plans?itm_referrer=editor-header-upgrade-prompt"
       target="_blank"
       onClick={handleClick}

+ 19 - 48
services/web/frontend/js/features/file-tree/components/file-tree-context-menu.tsx

@@ -9,7 +9,6 @@ import { useFileTreeData } from '@/shared/context/file-tree-data-context'
 import { useFileTreeMainContext } from '../contexts/file-tree-main'
 
 import FileTreeItemMenuItems from './file-tree-item/file-tree-item-menu-items'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function FileTreeContextMenu() {
   const { fileTreeReadOnly } = useFileTreeData()
@@ -47,10 +46,6 @@ function FileTreeContextMenu() {
     if (!wantOpen) close()
   }
 
-  function handleClick() {
-    handleToggle(false)
-  }
-
   // A11y - Close the context menu when the user presses the Tab key
   // Focus should move to the next element in the filetree
   function handleKeyDown(event: React.KeyboardEvent<BS3Dropdown | Element>) {
@@ -60,51 +55,27 @@ function FileTreeContextMenu() {
   }
 
   return ReactDOM.createPortal(
-    <BootstrapVersionSwitcher
-      bs3={
-        <BS3Dropdown
-          onClick={handleClick}
-          open
+    <div style={contextMenuCoords} className="context-menu">
+      <Dropdown
+        show
+        drop={
+          document.body.offsetHeight / contextMenuCoords.top < 2 &&
+          document.body.offsetHeight - contextMenuCoords.top < 250
+            ? 'up'
+            : 'down'
+        }
+        focusFirstItemOnShow // A11y - Focus the first item in the context menu when it opens since the menu is rendered at the root level
+        onKeyDown={handleKeyDown}
+        onToggle={handleToggle}
+      >
+        <DropdownMenu
+          className="dropdown-menu-sm-width"
           id="dropdown-file-tree-context-menu"
-          onToggle={handleToggle}
-          dropup={
-            document.body.offsetHeight / contextMenuCoords.top < 2 &&
-            document.body.offsetHeight - contextMenuCoords.top < 250
-          }
-          className="context-menu"
-          style={contextMenuCoords}
-          onKeyDown={handleKeyDown}
         >
-          <FakeDropDownToggle bsRole="toggle" />
-          <BS3Dropdown.Menu tabIndex={-1}>
-            <FileTreeItemMenuItems />
-          </BS3Dropdown.Menu>
-        </BS3Dropdown>
-      }
-      bs5={
-        <div style={contextMenuCoords} className="context-menu">
-          <Dropdown
-            show
-            drop={
-              document.body.offsetHeight / contextMenuCoords.top < 2 &&
-              document.body.offsetHeight - contextMenuCoords.top < 250
-                ? 'up'
-                : 'down'
-            }
-            focusFirstItemOnShow // A11y - Focus the first item in the context menu when it opens since the menu is rendered at the root level
-            onKeyDown={handleKeyDown}
-            onToggle={handleToggle}
-          >
-            <DropdownMenu
-              className="dropdown-menu-sm-width"
-              id="dropdown-file-tree-context-menu"
-            >
-              <FileTreeItemMenuItems />
-            </DropdownMenu>
-          </Dropdown>
-        </div>
-      }
-    />,
+          <FileTreeItemMenuItems />
+        </DropdownMenu>
+      </Dropdown>
+    </div>,
     document.body
   )
 }

+ 2 - 3
services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-body.jsx

@@ -11,7 +11,6 @@ import importOverleafModules from '../../../../../macros/import-overleaf-module.
 import { lazy, Suspense } from 'react'
 import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner'
 import getMeta from '@/utils/meta'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 const createFileModeModules = importOverleafModules('createFileModes')
 
@@ -40,7 +39,7 @@ export default function FileTreeModalCreateFileBody() {
             <ul className="list-unstyled">
               <FileTreeModalCreateFileMode
                 mode="doc"
-                icon={bsVersion({ bs5: 'description', bs3: 'file' })}
+                icon="description"
                 label={t('new_file')}
               />
 
@@ -54,7 +53,7 @@ export default function FileTreeModalCreateFileBody() {
                 hasLinkedProjectOutputFileFeature) && (
                 <FileTreeModalCreateFileMode
                   mode="project"
-                  icon={bsVersion({ bs5: 'folder_open', bs3: 'folder-open' })}
+                  icon="folder_open"
                   label={t('from_another_project')}
                 />
               )}

+ 0 - 1
services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-footer.jsx

@@ -66,7 +66,6 @@ export function FileTreeModalCreateFileFooterContent({
           form="create-file"
           disabled={inFlight || !valid}
           isLoading={inFlight}
-          bs3Props={{ loading: inFlight ? `${t('creating')}…` : t('create') }}
         >
           {t('create')}
         </OLButton>

+ 1 - 6
services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-mode.jsx

@@ -1,10 +1,8 @@
 import classnames from 'classnames'
 import PropTypes from 'prop-types'
-import Icon from '../../../../shared/components/icon'
 import { useFileTreeActionable } from '../../contexts/file-tree-actionable'
 import * as eventTracking from '../../../../infrastructure/event-tracking'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 export default function FileTreeModalCreateFileMode({ mode, icon, label }) {
@@ -22,10 +20,7 @@ export default function FileTreeModalCreateFileMode({ mode, icon, label }) {
         onClick={handleClick}
         className="modal-new-file-mode"
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type={icon} fw />}
-          bs5={<MaterialIcon type={icon} />}
-        />
+        <MaterialIcon type={icon} />
         &nbsp;
         {label}
       </OLButton>

+ 15 - 32
services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-import-from-project.tsx

@@ -5,7 +5,6 @@ import {
   useMemo,
   FormEventHandler,
 } from 'react'
-import Icon from '../../../../../shared/components/icon'
 import FileTreeCreateNameInput from '../file-tree-create-name-input'
 import { useTranslation } from 'react-i18next'
 import { useUserProjects } from '../../../hooks/use-user-projects'
@@ -25,7 +24,6 @@ import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
 import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
 import OLForm from '@/features/ui/components/ol/ol-form'
 import OLFormSelect from '@/features/ui/components/ol/ol-form-select'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { Spinner } from 'react-bootstrap-5'
 
 export default function FileTreeImportFromProject() {
@@ -216,16 +214,11 @@ function SelectProject({
       {loading && (
         <span>
           &nbsp;
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="spinner" spin />}
-            bs5={
-              <Spinner
-                animation="border"
-                aria-hidden="true"
-                size="sm"
-                role="status"
-              />
-            }
+          <Spinner
+            animation="border"
+            aria-hidden="true"
+            size="sm"
+            role="status"
           />
         </span>
       )}
@@ -287,16 +280,11 @@ function SelectProjectOutputFile({
       {loading && (
         <span>
           &nbsp;
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="spinner" spin />}
-            bs5={
-              <Spinner
-                animation="border"
-                aria-hidden="true"
-                size="sm"
-                role="status"
-              />
-            }
+          <Spinner
+            animation="border"
+            aria-hidden="true"
+            size="sm"
+            role="status"
           />
         </span>
       )}
@@ -351,16 +339,11 @@ function SelectProjectEntity({
       {loading && (
         <span>
           &nbsp;
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="spinner" spin />}
-            bs5={
-              <Spinner
-                animation="border"
-                aria-hidden="true"
-                size="sm"
-                role="status"
-              />
-            }
+          <Spinner
+            animation="border"
+            aria-hidden="true"
+            size="sm"
+            role="status"
           />
         </span>
       )}

+ 15 - 40
services/web/frontend/js/features/file-tree/components/file-tree-folder-icons.tsx

@@ -1,6 +1,4 @@
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import { useFeatureFlag } from '@/shared/context/split-test-context'
 
@@ -33,44 +31,21 @@ function FileTreeFolderIcons({
   }
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <>
-          <button
-            onClick={onExpandCollapseClick}
-            aria-label={expanded ? t('collapse') : t('expand')}
-          >
-            <Icon
-              type={expanded ? 'angle-down' : 'angle-right'}
-              fw
-              className="file-tree-expand-icon"
-            />
-          </button>
-          <Icon
-            type={expanded ? 'folder-open' : 'folder'}
-            fw
-            className="file-tree-folder-icon"
-          />
-        </>
-      }
-      bs5={
-        <>
-          <button
-            onClick={onExpandCollapseClick}
-            aria-label={expanded ? t('collapse') : t('expand')}
-          >
-            <MaterialIcon
-              type={expanded ? 'expand_more' : 'chevron_right'}
-              className="file-tree-expand-icon"
-            />
-          </button>
-          <MaterialIcon
-            type={expanded ? 'folder_open' : 'folder'}
-            className="file-tree-folder-icon"
-          />
-        </>
-      }
-    />
+    <>
+      <button
+        onClick={onExpandCollapseClick}
+        aria-label={expanded ? t('collapse') : t('expand')}
+      >
+        <MaterialIcon
+          type={expanded ? 'expand_more' : 'chevron_right'}
+          className="file-tree-expand-icon"
+        />
+      </button>
+      <MaterialIcon
+        type={expanded ? 'folder_open' : 'folder'}
+        className="file-tree-folder-icon"
+      />
+    </>
   )
 }
 

+ 9 - 30
services/web/frontend/js/features/file-tree/components/file-tree-icon.tsx

@@ -1,10 +1,8 @@
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
 import iconTypeFromName, {
   newEditorIconTypeFromName,
 } from '../util/icon-type-from-name'
 import classnames from 'classnames'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import { useFeatureFlag } from '@/shared/context/split-test-context'
 
@@ -46,34 +44,15 @@ function FileTreeIcon({
   return (
     <>
       &nbsp;
-      <BootstrapVersionSwitcher
-        bs3={
-          <>
-            <Icon type={iconTypeFromName(name)} fw className={className} />
-            {isLinkedFile && (
-              <Icon
-                type="external-link-square"
-                modifier="rotate-180"
-                className="linked-file-highlight"
-                accessibilityLabel={t('linked_file')}
-              />
-            )}
-          </>
-        }
-        bs5={
-          <>
-            <MaterialIcon type={iconTypeFromName(name)} className={className} />
-            {isLinkedFile && (
-              <MaterialIcon
-                type="open_in_new"
-                modifier="rotate-180"
-                className="linked-file-highlight"
-                accessibilityLabel={t('linked_file')}
-              />
-            )}
-          </>
-        }
-      />
+      <MaterialIcon type={iconTypeFromName(name)} className={className} />
+      {isLinkedFile && (
+        <MaterialIcon
+          type="open_in_new"
+          modifier="rotate-180"
+          className="linked-file-highlight"
+          accessibilityLabel={t('linked_file')}
+        />
+      )}
     </>
   )
 }

+ 41 - 76
services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu-items.tsx

@@ -3,13 +3,11 @@ import { useTranslation } from 'react-i18next'
 import * as eventTracking from '../../../../infrastructure/event-tracking'
 import { useProjectContext } from '@/shared/context/project-context'
 
-import { MenuItem } from 'react-bootstrap'
 import {
   DropdownDivider,
   DropdownItem,
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
 import { useFileTreeActionable } from '../../contexts/file-tree-actionable'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function FileTreeItemMenuItems() {
   const { t } = useTranslation()
@@ -47,82 +45,49 @@ function FileTreeItemMenuItems() {
   }, [startUploadingDocOrFile])
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
+    <>
+      {canRename ? (
+        <li role="none">
+          <DropdownItem onClick={startRenaming}>{t('rename')}</DropdownItem>
+        </li>
+      ) : null}
+      {downloadPath ? (
+        <li role="none">
+          <DropdownItem
+            href={downloadPath}
+            onClick={downloadWithAnalytics}
+            download={selectedFileName ?? undefined}
+          >
+            {t('download')}
+          </DropdownItem>
+        </li>
+      ) : null}
+      {canDelete ? (
+        <li role="none">
+          <DropdownItem onClick={startDeleting}>{t('delete')}</DropdownItem>
+        </li>
+      ) : null}
+      {canCreate ? (
         <>
-          {canRename ? (
-            <MenuItem onClick={startRenaming}>{t('rename')}</MenuItem>
-          ) : null}
-          {downloadPath ? (
-            <MenuItem
-              href={downloadPath}
-              onClick={downloadWithAnalytics}
-              download={selectedFileName}
-            >
-              {t('download')}
-            </MenuItem>
-          ) : null}
-          {canDelete ? (
-            <MenuItem onClick={startDeleting}>{t('delete')}</MenuItem>
-          ) : null}
-          {canCreate ? (
-            <>
-              <li role="none" className="divider" />
-              <MenuItem onClick={createWithAnalytics}>{t('new_file')}</MenuItem>
-              <MenuItem onClick={startCreatingFolder}>
-                {t('new_folder')}
-              </MenuItem>
-              <MenuItem onClick={uploadWithAnalytics}>{t('upload')}</MenuItem>
-            </>
-          ) : null}
+          <DropdownDivider />
+          <li role="none">
+            <DropdownItem onClick={createWithAnalytics}>
+              {t('new_file')}
+            </DropdownItem>
+          </li>
+          <li role="none">
+            <DropdownItem onClick={startCreatingFolder}>
+              {t('new_folder')}
+            </DropdownItem>
+          </li>
+          <li role="none">
+            <DropdownItem onClick={uploadWithAnalytics}>
+              {t('upload')}
+            </DropdownItem>
+          </li>
         </>
-      }
-      bs5={
-        <>
-          {canRename ? (
-            <li role="none">
-              <DropdownItem onClick={startRenaming}>{t('rename')}</DropdownItem>
-            </li>
-          ) : null}
-          {downloadPath ? (
-            <li role="none">
-              <DropdownItem
-                href={downloadPath}
-                onClick={downloadWithAnalytics}
-                download={selectedFileName ?? undefined}
-              >
-                {t('download')}
-              </DropdownItem>
-            </li>
-          ) : null}
-          {canDelete ? (
-            <li role="none">
-              <DropdownItem onClick={startDeleting}>{t('delete')}</DropdownItem>
-            </li>
-          ) : null}
-          {canCreate ? (
-            <>
-              <DropdownDivider />
-              <li role="none">
-                <DropdownItem onClick={createWithAnalytics}>
-                  {t('new_file')}
-                </DropdownItem>
-              </li>
-              <li role="none">
-                <DropdownItem onClick={startCreatingFolder}>
-                  {t('new_folder')}
-                </DropdownItem>
-              </li>
-              <li role="none">
-                <DropdownItem onClick={uploadWithAnalytics}>
-                  {t('upload')}
-                </DropdownItem>
-              </li>
-            </>
-          ) : null}
-        </>
-      }
-    />
+      ) : null}
+    </>
   )
 }
 

+ 1 - 6
services/web/frontend/js/features/file-tree/components/file-tree-item/file-tree-item-menu.tsx

@@ -1,8 +1,6 @@
 import { useRef } from 'react'
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../../shared/components/icon'
 import { useFileTreeMainContext } from '../../contexts/file-tree-main'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 function FileTreeItemMenu({ id, name }: { id: string; name: string }) {
@@ -36,10 +34,7 @@ function FileTreeItemMenu({ id, name }: { id: string; name: string }) {
         aria-expanded={isMenuOpen}
         aria-label={t('open_action_menu', { name })}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="ellipsis-v" accessibilityLabel={t('menu')} />}
-          bs5={<MaterialIcon type="more_vert" accessibilityLabel={t('menu')} />}
-        />
+        <MaterialIcon type="more_vert" accessibilityLabel={t('menu')} />
       </button>
     </div>
   )

+ 5 - 38
services/web/frontend/js/features/file-tree/components/file-tree-toolbar.tsx

@@ -1,10 +1,8 @@
 import { useTranslation } from 'react-i18next'
 import * as eventTracking from '../../../infrastructure/event-tracking'
-import Icon from '../../../shared/components/icon'
 import { useFileTreeActionable } from '../contexts/file-tree-actionable'
 import { useFileTreeData } from '@/shared/context/file-tree-data-context'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import OLButtonToolbar from '@/features/ui/components/ol/ol-button-toolbar'
 import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
@@ -60,15 +58,7 @@ function FileTreeToolbarLeft() {
         overlayProps={{ placement: 'bottom' }}
       >
         <button className="btn" onClick={createWithAnalytics}>
-          <BootstrapVersionSwitcher
-            bs5={
-              <MaterialIcon
-                type="description"
-                accessibilityLabel={t('new_file')}
-              />
-            }
-            bs3={<Icon type="file" fw accessibilityLabel={t('new_file')} />}
-          />
+          <MaterialIcon type="description" accessibilityLabel={t('new_file')} />
         </button>
       </OLTooltip>
       <OLTooltip
@@ -77,15 +67,7 @@ function FileTreeToolbarLeft() {
         overlayProps={{ placement: 'bottom' }}
       >
         <button className="btn" onClick={startCreatingFolder} tabIndex={-1}>
-          <BootstrapVersionSwitcher
-            bs5={
-              <MaterialIcon
-                type="folder"
-                accessibilityLabel={t('new_folder')}
-              />
-            }
-            bs3={<Icon type="folder" fw accessibilityLabel={t('new_folder')} />}
-          />
+          <MaterialIcon type="folder" accessibilityLabel={t('new_folder')} />
         </button>
       </OLTooltip>
       <OLTooltip
@@ -94,12 +76,7 @@ function FileTreeToolbarLeft() {
         overlayProps={{ placement: 'bottom' }}
       >
         <button className="btn" onClick={uploadWithAnalytics} tabIndex={-1}>
-          <BootstrapVersionSwitcher
-            bs5={
-              <MaterialIcon type="upload" accessibilityLabel={t('upload')} />
-            }
-            bs3={<Icon type="upload" fw accessibilityLabel={t('upload')} />}
-          />
+          <MaterialIcon type="upload" accessibilityLabel={t('upload')} />
         </button>
       </OLTooltip>
     </div>
@@ -126,12 +103,7 @@ function FileTreeToolbarRight() {
           overlayProps={{ placement: 'bottom' }}
         >
           <button className="btn" onClick={startRenaming} tabIndex={-1}>
-            <BootstrapVersionSwitcher
-              bs3={<Icon type="pencil" fw accessibilityLabel={t('rename')} />}
-              bs5={
-                <MaterialIcon type="edit" accessibilityLabel={t('rename')} />
-              }
-            />
+            <MaterialIcon type="edit" accessibilityLabel={t('rename')} />
           </button>
         </OLTooltip>
       ) : null}
@@ -143,12 +115,7 @@ function FileTreeToolbarRight() {
           overlayProps={{ placement: 'bottom' }}
         >
           <button className="btn" onClick={startDeleting} tabIndex={-1}>
-            <BootstrapVersionSwitcher
-              bs3={<Icon type="trash-o" fw accessibilityLabel={t('delete')} />}
-              bs5={
-                <MaterialIcon type="delete" accessibilityLabel={t('delete')} />
-              }
-            />
+            <MaterialIcon type="delete" accessibilityLabel={t('delete')} />
           </button>
         </OLTooltip>
       ) : null}

+ 1 - 6
services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-create-folder.jsx

@@ -83,12 +83,7 @@ function FileTreeModalCreateFolder() {
 
       <OLModalFooter>
         {inFlight ? (
-          <OLButton
-            variant="primary"
-            disabled
-            isLoading={inFlight}
-            bs3Props={{ loading: `${t('creating')}…` }}
-          />
+          <OLButton variant="primary" disabled isLoading={inFlight} />
         ) : (
           <>
             <OLButton variant="secondary" onClick={handleHide}>

+ 1 - 6
services/web/frontend/js/features/file-tree/components/modals/file-tree-modal-delete.jsx

@@ -55,12 +55,7 @@ function FileTreeModalDelete() {
 
       <OLModalFooter>
         {inFlight ? (
-          <OLButton
-            variant="danger"
-            disabled
-            isLoading
-            bs3Props={{ loading: `${t('deleting')}…` }}
-          />
+          <OLButton variant="danger" disabled isLoading />
         ) : (
           <>
             <OLButton variant="secondary" onClick={handleHide}>

+ 4 - 5
services/web/frontend/js/features/file-tree/util/icon-type-from-name.ts

@@ -1,4 +1,3 @@
-import { isBootstrap5 } from '@/features/utils/bootstrap-5'
 import { AvailableUnfilledIcon } from '@/shared/components/material-icon'
 
 // TODO ide-redesign-cleanup: Make this the default export and remove the legacy version
@@ -27,12 +26,12 @@ export default function iconTypeFromName(name: string): string {
   if (ext && ['png', 'pdf', 'jpg', 'jpeg', 'gif'].includes(ext)) {
     return 'image'
   } else if (ext && ['csv', 'xls', 'xlsx'].includes(ext)) {
-    return isBootstrap5() ? 'table_chart' : 'table'
+    return 'table_chart'
   } else if (ext && ['py', 'r'].includes(ext)) {
-    return isBootstrap5() ? 'code' : 'file-text'
+    return 'code'
   } else if (ext && ['bib'].includes(ext)) {
-    return isBootstrap5() ? 'menu_book' : 'book'
+    return 'menu_book'
   } else {
-    return isBootstrap5() ? 'description' : 'file'
+    return 'description'
   }
 }

+ 1 - 6
services/web/frontend/js/features/file-view/components/file-view-header.tsx

@@ -1,7 +1,6 @@
 import { useState, type ElementType } from 'react'
 import { Trans, useTranslation } from 'react-i18next'
 
-import Icon from '../../../shared/components/icon'
 import { formatTime, relativeDate } from '../../utils/format-date'
 import { fileUrl } from '../../utils/fileUrl'
 import { useFileTreeData } from '@/shared/context/file-tree-data-context'
@@ -14,7 +13,6 @@ import { BinaryFile, hasProvider, LinkedFile } from '../types/binary-file'
 import FileViewRefreshButton from './file-view-refresh-button'
 import FileViewRefreshError from './file-view-refresh-error'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import OLButton from '@/features/ui/components/ol/ol-button'
 
 const tprFileViewInfo = importOverleafModules('tprFileViewInfo') as {
@@ -87,10 +85,7 @@ export default function FileViewHeader({ file }: FileViewHeaderProps) {
           download={file.name}
           href={fileUrl(projectId, file.id, file.hash)}
         >
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="download" fw />}
-            bs5={<MaterialIcon type="download" className="align-middle" />}
-          />{' '}
+          <MaterialIcon type="download" className="align-middle" />{' '}
           <span>{t('download')}</span>
         </OLButton>
       </div>

+ 5 - 19
services/web/frontend/js/features/file-view/components/file-view-icons.jsx

@@ -1,26 +1,12 @@
-import Icon from '../../../shared/components/icon'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 export const LinkedFileIcon = props => {
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <Icon
-          type="external-link-square"
-          modifier="rotate-180"
-          className="linked-file-icon"
-          {...props}
-        />
-      }
-      bs5={
-        <MaterialIcon
-          type="open_in_new"
-          modifier="rotate-180"
-          className="align-middle linked-file-icon"
-          {...props}
-        />
-      }
+    <MaterialIcon
+      type="open_in_new"
+      modifier="rotate-180"
+      className="align-middle linked-file-icon"
+      {...props}
     />
   )
 }

+ 1 - 9
services/web/frontend/js/features/file-view/components/file-view-refresh-button.tsx

@@ -6,7 +6,6 @@ import {
   useState,
 } from 'react'
 import { useTranslation } from 'react-i18next'
-import Icon from '@/shared/components/icon'
 import { postJSON } from '@/infrastructure/fetch-json'
 import { useProjectContext } from '@/shared/context/project-context'
 import type { BinaryFile } from '../types/binary-file'
@@ -103,14 +102,7 @@ function FileViewRefreshButtonDefault({
       onClick={() => refreshFile(null)}
       disabled={refreshing}
       isLoading={refreshing}
-      bs3Props={{
-        loading: (
-          <>
-            <Icon type="refresh" spin={refreshing} fw />{' '}
-            <span>{refreshing ? `${t('refreshing')}…` : t('refresh')}</span>
-          </>
-        ),
-      }}
+      loadingLabel={t('refreshing')}
     >
       {t('refresh')}
     </OLButton>

+ 0 - 5
services/web/frontend/js/features/history/components/change-list/add-label-modal.tsx

@@ -117,11 +117,6 @@ function AddLabelModal({ show, setShow, version }: AddLabelModalProps) {
             variant="primary"
             disabled={isLoading || !comment.length}
             isLoading={isLoading}
-            bs3Props={{
-              loading: isLoading
-                ? t('history_adding_label')
-                : t('history_add_label'),
-            }}
           >
             {t('history_add_label')}
           </OLButton>

+ 0 - 4
services/web/frontend/js/features/history/components/change-list/all-history-list.tsx

@@ -192,11 +192,9 @@ function AllHistoryList() {
             },
           ],
         }}
-        bs3Props={{ shouldUpdatePosition: true }}
       >
         <OLPopover
           id="popover-react-history-tutorial"
-          bs3Props={{ arrowOffsetTop: 10 }}
           title={
             <span>
               {t('react_history_tutorial_title')}{' '}
@@ -236,11 +234,9 @@ function AllHistoryList() {
         onHide={hidePopover}
         // using scrollerRef to position the popover in the middle of the viewport
         target={scrollerRef.current}
-        bs3Props={{ shouldUpdatePosition: true }}
       >
         <OLPopover
           id="popover-history-restore-promo"
-          bs3Props={{ arrowOffsetTop: 10 }}
           title={
             <span>
               {t('history_restore_promo_title')}

+ 2 - 75
services/web/frontend/js/features/history/components/change-list/dropdown/actions-dropdown.tsx

@@ -1,13 +1,9 @@
-import React, { useRef, useEffect, ReactNode } from 'react'
-import { Dropdown as BS3Dropdown } from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
+import React, { ReactNode } from 'react'
 import {
   Dropdown,
   DropdownMenu,
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
-import BS3DropdownToggleWithTooltip from '../../../../ui/components/bootstrap-3/dropdown-toggle-with-tooltip'
 import BS5DropdownToggleWithTooltip from '@/features/ui/components/bootstrap-5/dropdown-toggle-with-tooltip'
-import DropdownMenuWithRef from '../../../../ui/components/bootstrap-3/dropdown-menu-with-ref'
 
 type ActionDropdownProps = {
   id: string
@@ -19,70 +15,6 @@ type ActionDropdownProps = {
   setIsOpened: (isOpened: boolean) => void
 }
 
-function BS3ActionsDropdown({
-  id,
-  children,
-  parentSelector,
-  isOpened,
-  iconTag,
-  setIsOpened,
-  toolTipDescription,
-}: ActionDropdownProps) {
-  const menuRef = useRef<HTMLElement>()
-
-  // handle the placement of the dropdown above or below the toggle button
-  useEffect(() => {
-    if (menuRef.current && parentSelector) {
-      const parent = menuRef.current.closest(parentSelector)
-
-      if (!parent) {
-        return
-      }
-
-      const parentBottom = parent.getBoundingClientRect().bottom
-      const { top, height } = menuRef.current.getBoundingClientRect()
-
-      if (top + height > parentBottom) {
-        menuRef.current.style.bottom = '100%'
-        menuRef.current.style.top = 'auto'
-      } else {
-        menuRef.current.style.bottom = 'auto'
-        menuRef.current.style.top = '100%'
-      }
-    }
-  })
-
-  return (
-    <BS3Dropdown
-      id={`history-version-dropdown-${id}`}
-      pullRight
-      open={isOpened}
-      onToggle={open => setIsOpened(open)}
-      className="pull-right"
-    >
-      <BS3DropdownToggleWithTooltip
-        bsRole="toggle"
-        className="history-version-dropdown-menu-btn"
-        isOpened={isOpened}
-        tooltipProps={{
-          id,
-          description: toolTipDescription,
-          overlayProps: { placement: 'bottom', trigger: ['hover'] },
-        }}
-      >
-        {iconTag}
-      </BS3DropdownToggleWithTooltip>
-      <DropdownMenuWithRef
-        bsRole="menu"
-        className="history-version-dropdown-menu"
-        menuRef={menuRef}
-      >
-        {children}
-      </DropdownMenuWithRef>
-    </BS3Dropdown>
-  )
-}
-
 function BS5ActionsDropdown({
   id,
   children,
@@ -116,12 +48,7 @@ function BS5ActionsDropdown({
 }
 
 function ActionsDropdown(props: ActionDropdownProps) {
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3ActionsDropdown {...props} />}
-      bs5={<BS5ActionsDropdown {...props} />}
-    />
-  )
+  return <BS5ActionsDropdown {...props} />
 }
 
 export default ActionsDropdown

+ 1 - 13
services/web/frontend/js/features/history/components/change-list/dropdown/history-dropdown.tsx

@@ -1,8 +1,6 @@
 import ActionsDropdown from './actions-dropdown'
-import Icon from '../../../../../shared/components/icon'
 import { useTranslation } from 'react-i18next'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 type HistoryDropdownProps = {
   children: React.ReactNode
@@ -25,17 +23,7 @@ function HistoryDropdown({
       toolTipDescription={t('more_actions')}
       setIsOpened={setIsOpened}
       iconTag={
-        <BootstrapVersionSwitcher
-          bs3={
-            <Icon type="ellipsis-v" accessibilityLabel={t('more_actions')} />
-          }
-          bs5={
-            <MaterialIcon
-              type="more_vert"
-              accessibilityLabel={t('more_actions')}
-            />
-          }
-        />
+        <MaterialIcon type="more_vert" accessibilityLabel={t('more_actions')} />
       }
       parentSelector="[data-history-version-list-container]"
     >

+ 1 - 4
services/web/frontend/js/features/history/components/change-list/dropdown/menu-item/compare.tsx

@@ -2,7 +2,6 @@ import { useHistoryContext } from '../../../../context/history-context'
 import { UpdateRange } from '../../../../services/types/update'
 import { ReactNode } from 'react'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 type CompareProps = {
   comparisonRange: UpdateRange
@@ -38,9 +37,7 @@ function Compare({
       overlayProps={{ placement: 'left' }}
     >
       <button className="history-compare-btn" onClick={handleCompareVersion}>
-        <span className={bsVersion({ bs3: 'sr-only', bs5: 'visually-hidden' })}>
-          {toolTipDescription}
-        </span>
+        <span className="visually-hidden">{toolTipDescription}</span>
         {icon}
       </button>
     </OLTooltip>

+ 1 - 8
services/web/frontend/js/features/history/components/change-list/dropdown/menu-item/download.tsx

@@ -1,8 +1,6 @@
 import { useTranslation } from 'react-i18next'
 import OLDropdownMenuItem from '@/features/ui/components/ol/ol-dropdown-menu-item'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import Icon from '../../../../../../shared/components/icon'
 
 type DownloadProps = {
   projectId: string
@@ -24,12 +22,7 @@ function Download({
       download={`${projectId}_v${version}.zip`}
       rel="noreferrer"
       onClick={closeDropdown}
-      leadingIcon={
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="cloud-download" fw />}
-          bs5={<MaterialIcon type="download" />}
-        />
-      }
+      leadingIcon={<MaterialIcon type="download" />}
       {...props}
     >
       {t('history_download_this_version')}

+ 1 - 8
services/web/frontend/js/features/history/components/change-list/dropdown/menu-item/restore-project.tsx

@@ -1,4 +1,3 @@
-import Icon from '@/shared/components/icon'
 import { useCallback, useState } from 'react'
 import OLDropdownMenuItem from '@/features/ui/components/ol/ol-dropdown-menu-item'
 import { useTranslation } from 'react-i18next'
@@ -8,7 +7,6 @@ import { useRestoreProject } from '@/features/history/context/hooks/use-restore-
 import withErrorBoundary from '@/infrastructure/error-boundary'
 import { RestoreProjectErrorModal } from '../../../diff-view/modals/restore-project-error-modal'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 type RestoreProjectProps = {
   projectId: string
@@ -48,12 +46,7 @@ const RestoreProject = ({
     <>
       <OLDropdownMenuItem
         as="button"
-        leadingIcon={
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="undo" fw />}
-            bs5={<MaterialIcon type="undo" />}
-          />
-        }
+        leadingIcon={<MaterialIcon type="undo" />}
         onClick={handleClick}
       >
         {t('restore_project_to_this_version')}

+ 1 - 5
services/web/frontend/js/features/history/components/change-list/history-version.tsx

@@ -22,7 +22,6 @@ import { CompareVersionDropdownContentAllHistory } from './dropdown/compare-vers
 import FileRestoreChange from './file-restore-change'
 import HistoryResyncChange from './history-resync-change'
 import ProjectRestoreChange from './project-restore-change'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 type HistoryVersionProps = {
   update: LoadedUpdate
@@ -124,10 +123,7 @@ function HistoryVersion({
           )}
 
           {selectionState !== 'selected' && !faded ? (
-            <div
-              data-testid="compare-icon-version"
-              className={bsVersion({ bs3: 'pull-right', bs5: 'float-end' })}
-            >
+            <div data-testid="compare-icon-version" className="float-end">
               {selectionState !== 'withinSelected' ? (
                 <CompareItems
                   updateRange={updateRange}

+ 1 - 5
services/web/frontend/js/features/history/components/change-list/label-list-item.tsx

@@ -13,7 +13,6 @@ import { ItemSelectionState } from '../../utils/history-details'
 import CompareVersionDropdown from './dropdown/compare-version-dropdown'
 import { CompareVersionDropdownContentLabelsList } from './dropdown/compare-version-dropdown-content'
 import HistoryDropdownContent from '@/features/history/components/change-list/dropdown/history-dropdown-content'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 type LabelListItemProps = {
   version: Version
@@ -97,10 +96,7 @@ function LabelListItem({
         ) : null}
       </HistoryDropdown>
       {selectionState !== 'selected' ? (
-        <div
-          data-testid="compare-icon-version"
-          className={bsVersion({ bs3: 'pull-right', bs5: 'float-end' })}
-        >
+        <div data-testid="compare-icon-version" className="float-end">
           {selectionState !== 'withinSelected' ? (
             <CompareItems
               updateRange={updateRange}

+ 0 - 5
services/web/frontend/js/features/history/components/change-list/tag-tooltip.tsx

@@ -122,11 +122,6 @@ const ChangeTag = forwardRef<HTMLElement, TagProps>(
                 disabled={isLoading}
                 isLoading={isLoading}
                 onClick={localDeleteHandler}
-                bs3Props={{
-                  loading: isLoading
-                    ? t('history_deleting_label')
-                    : t('history_delete_label'),
-                }}
               >
                 {t('history_delete_label')}
               </OLButton>

+ 2 - 3
services/web/frontend/js/features/history/components/diff-view/document-diff-viewer.tsx

@@ -21,7 +21,6 @@ import {
 import { useTranslation } from 'react-i18next'
 import { inlineBackground } from '../../../source-editor/extensions/inline-background'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 function extensions(themeOptions: Options): Extension[] {
   return [
@@ -134,7 +133,7 @@ function DocumentDiffViewer({
       {before > 0 ? (
         <OLButton
           variant="secondary"
-          leadingIcon={bsVersion({ bs3: 'arrow-up', bs5: 'arrow_upward' })}
+          leadingIcon="arrow_upward"
           onClick={scrollToPrevious}
           className="previous-highlight-button"
         >
@@ -144,7 +143,7 @@ function DocumentDiffViewer({
       {after > 0 ? (
         <OLButton
           variant="secondary"
-          leadingIcon={bsVersion({ bs3: 'arrow-down', bs5: 'arrow_downward' })}
+          leadingIcon="arrow_downward"
           onClick={scrollToNext}
           className="next-highlight-button"
         >

+ 0 - 1
services/web/frontend/js/features/history/components/diff-view/modals/restore-project-modal.tsx

@@ -51,7 +51,6 @@ export const RestoreProjectModal = ({
           onClick={onRestore}
           disabled={isRestoring}
           isLoading={isRestoring}
-          bs3Props={{ loading: isRestoring ? t('restoring') : t('restore') }}
         >
           {t('restore')}
         </OLButton>

+ 0 - 4
services/web/frontend/js/features/history/components/diff-view/toolbar/toolbar-restore-file-button.tsx

@@ -21,10 +21,6 @@ export default function ToolbarRestoreFileButton({
       className="history-react-toolbar-restore-file-button"
       isLoading={isLoading}
       onClick={() => restoreDeletedFile(selection)}
-      bs3Props={{
-        bsSize: 'xsmall',
-        loading: isLoading ? `${t('restoring')}…` : t('restore_file'),
-      }}
     >
       {t('restore_file')}
     </OLButton>

+ 0 - 4
services/web/frontend/js/features/history/components/diff-view/toolbar/toolbar-restore-file-to-version-button.tsx

@@ -38,10 +38,6 @@ function ToolbarRestoreFileToVersionButton({
         size="sm"
         isLoading={isLoading}
         onClick={() => setShowConfirmModal(true)}
-        bs3Props={{
-          bsSize: 'xsmall',
-          loading: isLoading ? `${t('restoring')}…` : t('restore_file_version'),
-        }}
       >
         {t('restore_file_version')}
       </OLButton>

+ 3 - 16
services/web/frontend/js/features/history/components/file-tree/history-file-tree-doc.tsx

@@ -2,9 +2,7 @@ import { memo } from 'react'
 import classNames from 'classnames'
 import HistoryFileTreeItem from './history-file-tree-item'
 import iconTypeFromName from '../../../file-tree/util/icon-type-from-name'
-import Icon from '../../../../shared/components/icon'
 import type { FileDiff } from '../../services/types/file'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 type HistoryFileTreeDocProps = {
@@ -36,20 +34,9 @@ function HistoryFileTreeDoc({
         name={name}
         operation={'operation' in file ? file.operation : undefined}
         icons={
-          <BootstrapVersionSwitcher
-            bs3={
-              <Icon
-                type={iconTypeFromName(name)}
-                fw
-                className="file-tree-icon"
-              />
-            }
-            bs5={
-              <MaterialIcon
-                type={iconTypeFromName(name)}
-                className="file-tree-icon"
-              />
-            }
+          <MaterialIcon
+            type={iconTypeFromName(name)}
+            className="file-tree-icon"
           />
         }
       />

+ 16 - 42
services/web/frontend/js/features/history/components/file-tree/history-file-tree-folder.tsx

@@ -4,9 +4,7 @@ import { useTranslation } from 'react-i18next'
 import HistoryFileTreeItem from './history-file-tree-item'
 import HistoryFileTreeFolderList from './history-file-tree-folder-list'
 
-import Icon from '../../../../shared/components/icon'
 import type { HistoryDoc, HistoryFileTree } from '../../utils/file-tree'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 type HistoryFileTreeFolderProps = {
@@ -43,46 +41,22 @@ function HistoryFileTreeFolder({
   })
 
   const icons = (
-    <BootstrapVersionSwitcher
-      bs3={
-        <>
-          <button
-            onClick={() => setExpanded(!expanded)}
-            aria-label={expanded ? t('collapse') : t('expand')}
-            className="history-file-tree-folder-button"
-          >
-            <Icon
-              type={expanded ? 'angle-down' : 'angle-right'}
-              fw
-              className="file-tree-expand-icon"
-            />
-          </button>
-          <Icon
-            type={expanded ? 'folder-open' : 'folder'}
-            fw
-            className="file-tree-folder-icon"
-          />
-        </>
-      }
-      bs5={
-        <>
-          <button
-            onClick={() => setExpanded(!expanded)}
-            aria-label={expanded ? t('collapse') : t('expand')}
-            className="history-file-tree-folder-button"
-          >
-            <MaterialIcon
-              type={expanded ? 'expand_more' : 'chevron_right'}
-              className="file-tree-expand-icon"
-            />
-          </button>
-          <MaterialIcon
-            type={expanded ? 'folder_open' : 'folder'}
-            className="file-tree-folder-icon"
-          />
-        </>
-      }
-    />
+    <>
+      <button
+        onClick={() => setExpanded(!expanded)}
+        aria-label={expanded ? t('collapse') : t('expand')}
+        className="history-file-tree-folder-button"
+      >
+        <MaterialIcon
+          type={expanded ? 'expand_more' : 'chevron_right'}
+          className="file-tree-expand-icon"
+        />
+      </button>
+      <MaterialIcon
+        type={expanded ? 'folder_open' : 'folder'}
+        className="file-tree-folder-icon"
+      />
+    </>
   )
 
   return (

+ 0 - 1
services/web/frontend/js/features/ide-react/components/alerts/alerts.tsx

@@ -61,7 +61,6 @@ export function Alerts() {
               id="synctex-more-info-button"
               variant="secondary"
               size="sm"
-              bs3Props={{ className: 'alert-link-as-btn pull-right' }}
             >
               {t('more_info')}
             </OLButton>

+ 0 - 1
services/web/frontend/js/features/ide-react/components/alerts/lost-connection-alert.tsx

@@ -40,7 +40,6 @@ export function LostConnectionAlert({
           onClick={() => tryReconnectNow()}
           size="sm"
           variant="secondary"
-          bs3Props={{ className: 'pull-right' }}
         >
           {t('try_now')}
         </OLButton>

+ 2 - 31
services/web/frontend/js/features/pdf-preview/components/detach-compile-button.tsx

@@ -1,12 +1,9 @@
 import { useTranslation } from 'react-i18next'
 import { memo } from 'react'
 import classnames from 'classnames'
-import Icon from '../../../shared/components/icon'
 import { useDetachCompileContext } from '../../../shared/context/detach-compile-context'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import { bsVersion } from '@/features/utils/bootstrap-5'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 const modifierKey = /Mac/i.test(navigator.platform) ? 'Cmd' : 'Ctrl'
 
@@ -14,7 +11,6 @@ function DetachCompileButton() {
   const { t } = useTranslation()
   const { compiling, startCompile, hasChanges } = useDetachCompileContext()
 
-  const compileButtonLabel = compiling ? `${t('compiling')}…` : t('recompile')
   const tooltipElement = (
     <>
       {t('recompile_pdf')}{' '}
@@ -23,12 +19,7 @@ function DetachCompileButton() {
   )
 
   return (
-    <div
-      className={classnames(
-        'detach-compile-button-container',
-        bsVersion({ bs5: 'ms-1' })
-      )}
-    >
+    <div className="detach-compile-button-container ms-1">
       <OLTooltip
         id="detach-compile"
         description={tooltipElement}
@@ -45,28 +36,8 @@ function DetachCompileButton() {
           })}
           size="sm"
           isLoading={compiling}
-          bs3Props={{
-            loading: compiling && (
-              <>
-                <Icon type="refresh" spin={compiling} />
-                <span className="detach-compile-button-label">
-                  {compileButtonLabel}
-                </span>
-              </>
-            ),
-          }}
         >
-          <BootstrapVersionSwitcher
-            bs3={
-              <>
-                <Icon type="refresh" spin={compiling} />
-                <span className="detach-compile-button-label">
-                  {compileButtonLabel}
-                </span>
-              </>
-            }
-            bs5={t('recompile')}
-          />
+          {t('recompile')}
         </OLButton>
       </OLTooltip>
     </div>

+ 1 - 14
services/web/frontend/js/features/pdf-preview/components/pdf-clear-cache-button.tsx

@@ -1,9 +1,7 @@
-import Icon from '../../../shared/components/icon'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import { useTranslation } from 'react-i18next'
 import { memo } from 'react'
 import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function PdfClearCacheButton() {
   const { compiling, clearCache, clearingCache } = useCompileContext()
@@ -19,19 +17,8 @@ function PdfClearCacheButton() {
       isLoading={clearingCache}
       disabled={clearingCache || compiling}
       leadingIcon="delete"
+      loadingLabel={t('clear_cached_files')}
     >
-      <BootstrapVersionSwitcher
-        bs3={
-          <>
-            {clearingCache ? (
-              <Icon type="refresh" spin />
-            ) : (
-              <Icon type="trash-o" />
-            )}
-            &nbsp;
-          </>
-        }
-      />
       <span>{t('clear_cached_files')}</span>
     </OLButton>
   )

+ 2 - 16
services/web/frontend/js/features/pdf-preview/components/pdf-code-check-failed-notice.tsx

@@ -1,28 +1,14 @@
 import { memo } from 'react'
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
 import OLNotification from '@/features/ui/components/ol/ol-notification'
-import { bsVersion } from '@/features/utils/bootstrap-5'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function PdfCodeCheckFailedNotice() {
   const { t } = useTranslation()
   return (
     <OLNotification
       type="error"
-      content={
-        <>
-          <BootstrapVersionSwitcher
-            bs3={
-              <>
-                <Icon type="exclamation-triangle" fw />{' '}
-              </>
-            }
-          />
-          {t('code_check_failed_explanation')}
-        </>
-      }
-      className={bsVersion({ bs5: 'm-0', bs3: 'mb-2' })}
+      content={t('code_check_failed_explanation')}
+      className="m-0"
     />
   )
 }

+ 115 - 249
services/web/frontend/js/features/pdf-preview/components/pdf-compile-button.tsx

@@ -3,10 +3,7 @@ import { memo } from 'react'
 import classNames from 'classnames'
 import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
 import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-error'
-import SplitMenu from '../../../shared/components/split-menu'
-import Icon from '../../../shared/components/icon'
 import * as eventTracking from '../../../infrastructure/event-tracking'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import {
   DropdownToggleCustom,
@@ -19,7 +16,6 @@ import {
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButtonGroup from '@/features/ui/components/ol/ol-button-group'
-import { bsVersion, isBootstrap5 } from '@/features/utils/bootstrap-5'
 import { useLayoutContext } from '@/shared/context/layout-context'
 
 const modifierKey = /Mac/i.test(navigator.platform) ? 'Cmd' : 'Ctrl'
@@ -43,7 +39,6 @@ function PdfCompileButton() {
     compiling,
     draft,
     hasChanges,
-    setAnimateCompileDropdownArrow,
     setAutoCompile,
     setDraft,
     setStopOnValidationError,
@@ -67,7 +62,6 @@ function PdfCompileButton() {
     recompileFromScratch()
   }
 
-  const compileButtonLabel = compiling ? `${t('compiling')}…` : t('recompile')
   const tooltipElement = (
     <>
       {t('recompile_pdf')}{' '}
@@ -81,288 +75,160 @@ function PdfCompileButton() {
       'btn-striped-animated': hasChanges,
     },
     'no-left-border',
-    bsVersion({ bs5: 'dropdown-button-toggle' })
+    'dropdown-button-toggle'
   )
 
   const buttonClassName = classNames(
+    'align-items-center py-0 no-left-radius px-3',
     {
       'btn-striped-animated': hasChanges,
-      'align-items-center py-0': isBootstrap5(),
-    },
-    'no-left-radius px-3'
+    }
   )
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <SplitMenu
-          bsStyle="primary"
-          bsSize="xs"
+    <Dropdown as={OLButtonGroup} className="compile-button-group">
+      <OLTooltip
+        description={tooltipElement}
+        id="compile"
+        tooltipProps={{ className: 'keyboard-tooltip' }}
+        overlayProps={{
+          delay: { show: 500, hide: 0 },
+          placement: detachRole === 'detached' ? 'bottom' : undefined,
+        }}
+      >
+        <OLButton
+          variant="primary"
           disabled={compiling}
-          button={{
-            tooltip: {
-              description: tooltipElement,
-              id: 'compile',
-              tooltipProps: { className: 'keyboard-tooltip' },
-              overlayProps: {
-                delayShow: 500,
-                placement: detachRole === 'detached' ? 'bottom' : undefined,
-              },
-            },
-            icon: { type: 'refresh', spin: compiling },
-            onClick: () => startCompile(),
-            text: compileButtonLabel,
-            className: buttonClassName,
-          }}
-          dropdownToggle={{
-            'aria-label': t('toggle_compile_options_menu'),
-            handleAnimationEnd: () => setAnimateCompileDropdownArrow(false),
-            className: dropdownToggleClassName,
-          }}
-          dropdown={{
-            id: 'pdf-recompile-dropdown',
-          }}
+          isLoading={compiling}
+          onClick={() => startCompile()}
+          className={buttonClassName}
+          loadingLabel={`${t('compiling')}…`}
         >
-          <SplitMenu.Item header>{t('auto_compile')}</SplitMenu.Item>
-
-          <SplitMenu.Item
-            onSelect={() =>
+          {t('recompile')}
+        </OLButton>
+      </OLTooltip>
+
+      <DropdownToggle
+        as={DropdownToggleCustom}
+        split
+        variant="primary"
+        id="pdf-recompile-dropdown"
+        size="sm"
+        aria-label={t('toggle_compile_options_menu')}
+        className={dropdownToggleClassName}
+      />
+
+      <DropdownMenu>
+        <DropdownHeader>{t('auto_compile')}</DropdownHeader>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={() =>
               sendEventAndSet(true, setAutoCompile, 'auto-compile')
             }
+            trailingIcon={autoCompile ? 'check' : null}
           >
-            <Icon type={autoCompile ? 'check' : ''} fw />
             {t('on')}
-          </SplitMenu.Item>
-
-          <SplitMenu.Item
-            onSelect={() =>
+          </DropdownItem>
+        </li>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={() =>
               sendEventAndSet(false, setAutoCompile, 'auto-compile')
             }
+            trailingIcon={!autoCompile ? 'check' : null}
           >
-            <Icon type={!autoCompile ? 'check' : ''} fw />
             {t('off')}
-          </SplitMenu.Item>
-
-          <SplitMenu.Item header>{t('compile_mode')}</SplitMenu.Item>
-
-          <SplitMenu.Item
-            onSelect={() => sendEventAndSet(false, setDraft, 'compile-mode')}
+          </DropdownItem>
+        </li>
+        <DropdownDivider />
+        <DropdownHeader>{t('compile_mode')}</DropdownHeader>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={() => sendEventAndSet(false, setDraft, 'compile-mode')}
+            trailingIcon={!draft ? 'check' : null}
           >
-            <Icon type={!draft ? 'check' : ''} fw />
             {t('normal')}
-          </SplitMenu.Item>
-
-          <SplitMenu.Item
-            onSelect={() => sendEventAndSet(true, setDraft, 'compile-mode')}
+          </DropdownItem>
+        </li>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={() => sendEventAndSet(true, setDraft, 'compile-mode')}
+            trailingIcon={draft ? 'check' : null}
           >
-            <Icon type={draft ? 'check' : ''} fw />
-            {t('fast')} <span className="subdued">[draft]</span>
-          </SplitMenu.Item>
-
-          <SplitMenu.Item header>Syntax Checks</SplitMenu.Item>
-
-          <SplitMenu.Item
-            onSelect={() =>
+            {t('fast')}&nbsp;<span className="subdued">[draft]</span>
+          </DropdownItem>
+        </li>
+        <DropdownDivider />
+        <DropdownHeader>Syntax Checks</DropdownHeader>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={() =>
               sendEventAndSet(true, setStopOnValidationError, 'syntax-check')
             }
+            trailingIcon={stopOnValidationError ? 'check' : null}
           >
-            <Icon type={stopOnValidationError ? 'check' : ''} fw />
             {t('stop_on_validation_error')}
-          </SplitMenu.Item>
-
-          <SplitMenu.Item
-            onSelect={() =>
+          </DropdownItem>
+        </li>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={() =>
               sendEventAndSet(false, setStopOnValidationError, 'syntax-check')
             }
+            trailingIcon={!stopOnValidationError ? 'check' : null}
           >
-            <Icon type={!stopOnValidationError ? 'check' : ''} fw />
             {t('ignore_validation_errors')}
-          </SplitMenu.Item>
-
-          <SplitMenu.Item header>{t('compile_error_handling')}</SplitMenu.Item>
-
-          <SplitMenu.Item onSelect={enableStopOnFirstError}>
-            <Icon type={stopOnFirstError ? 'check' : ''} fw />
+          </DropdownItem>
+        </li>
+        <DropdownDivider />
+        <DropdownHeader>{t('compile_error_handling')}</DropdownHeader>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={enableStopOnFirstError}
+            trailingIcon={stopOnFirstError ? 'check' : null}
+          >
             {t('stop_on_first_error')}
-          </SplitMenu.Item>
-
-          <SplitMenu.Item onSelect={disableStopOnFirstError}>
-            <Icon type={!stopOnFirstError ? 'check' : ''} fw />
+          </DropdownItem>
+        </li>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={disableStopOnFirstError}
+            trailingIcon={!stopOnFirstError ? 'check' : null}
+          >
             {t('try_to_compile_despite_errors')}
-          </SplitMenu.Item>
-
-          <SplitMenu.Item divider />
-
-          <SplitMenu.Item
-            onSelect={() => stopCompile()}
+          </DropdownItem>
+        </li>
+        <DropdownDivider />
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={() => stopCompile()}
             disabled={!compiling}
             aria-disabled={!compiling}
           >
             {t('stop_compile')}
-          </SplitMenu.Item>
-
-          <SplitMenu.Item
-            onSelect={fromScratchWithEvent}
+          </DropdownItem>
+        </li>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            onClick={fromScratchWithEvent}
             disabled={compiling}
             aria-disabled={compiling}
           >
             {t('recompile_from_scratch')}
-          </SplitMenu.Item>
-        </SplitMenu>
-      }
-      bs5={
-        <Dropdown as={OLButtonGroup} className="compile-button-group">
-          <OLTooltip
-            description={tooltipElement}
-            id="compile"
-            tooltipProps={{ className: 'keyboard-tooltip' }}
-            overlayProps={{
-              delay: { show: 500, hide: 0 },
-              placement: detachRole === 'detached' ? 'bottom' : undefined,
-            }}
-          >
-            <OLButton
-              variant="primary"
-              disabled={compiling}
-              isLoading={compiling}
-              onClick={() => startCompile()}
-              className={buttonClassName}
-            >
-              {t('recompile')}
-            </OLButton>
-          </OLTooltip>
-
-          <DropdownToggle
-            as={DropdownToggleCustom}
-            split
-            variant="primary"
-            id="pdf-recompile-dropdown"
-            size="sm"
-            aria-label={t('toggle_compile_options_menu')}
-            className={dropdownToggleClassName}
-          />
-
-          <DropdownMenu>
-            <DropdownHeader>{t('auto_compile')}</DropdownHeader>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={() =>
-                  sendEventAndSet(true, setAutoCompile, 'auto-compile')
-                }
-                trailingIcon={autoCompile ? 'check' : null}
-              >
-                {t('on')}
-              </DropdownItem>
-            </li>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={() =>
-                  sendEventAndSet(false, setAutoCompile, 'auto-compile')
-                }
-                trailingIcon={!autoCompile ? 'check' : null}
-              >
-                {t('off')}
-              </DropdownItem>
-            </li>
-            <DropdownDivider />
-            <DropdownHeader>{t('compile_mode')}</DropdownHeader>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={() => sendEventAndSet(false, setDraft, 'compile-mode')}
-                trailingIcon={!draft ? 'check' : null}
-              >
-                {t('normal')}
-              </DropdownItem>
-            </li>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={() => sendEventAndSet(true, setDraft, 'compile-mode')}
-                trailingIcon={draft ? 'check' : null}
-              >
-                {t('fast')}&nbsp;<span className="subdued">[draft]</span>
-              </DropdownItem>
-            </li>
-            <DropdownDivider />
-            <DropdownHeader>Syntax Checks</DropdownHeader>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={() =>
-                  sendEventAndSet(
-                    true,
-                    setStopOnValidationError,
-                    'syntax-check'
-                  )
-                }
-                trailingIcon={stopOnValidationError ? 'check' : null}
-              >
-                {t('stop_on_validation_error')}
-              </DropdownItem>
-            </li>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={() =>
-                  sendEventAndSet(
-                    false,
-                    setStopOnValidationError,
-                    'syntax-check'
-                  )
-                }
-                trailingIcon={!stopOnValidationError ? 'check' : null}
-              >
-                {t('ignore_validation_errors')}
-              </DropdownItem>
-            </li>
-            <DropdownDivider />
-            <DropdownHeader>{t('compile_error_handling')}</DropdownHeader>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={enableStopOnFirstError}
-                trailingIcon={stopOnFirstError ? 'check' : null}
-              >
-                {t('stop_on_first_error')}
-              </DropdownItem>
-            </li>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={disableStopOnFirstError}
-                trailingIcon={!stopOnFirstError ? 'check' : null}
-              >
-                {t('try_to_compile_despite_errors')}
-              </DropdownItem>
-            </li>
-            <DropdownDivider />
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={() => stopCompile()}
-                disabled={!compiling}
-                aria-disabled={!compiling}
-              >
-                {t('stop_compile')}
-              </DropdownItem>
-            </li>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                onClick={fromScratchWithEvent}
-                disabled={compiling}
-                aria-disabled={compiling}
-              >
-                {t('recompile_from_scratch')}
-              </DropdownItem>
-            </li>
-          </DropdownMenu>
-        </Dropdown>
-      }
-    />
+          </DropdownItem>
+        </li>
+      </DropdownMenu>
+    </Dropdown>
   )
 }
 

+ 13 - 39
services/web/frontend/js/features/pdf-preview/components/pdf-download-files-button.tsx

@@ -1,16 +1,12 @@
-import { Dropdown as BS3Dropdown } from 'react-bootstrap'
-
 import {
   Dropdown,
   DropdownMenu,
   DropdownToggle,
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
 import PdfFileList from './pdf-file-list'
-import ControlledDropdown from '../../../shared/components/controlled-dropdown'
 import { memo } from 'react'
 import { useTranslation } from 'react-i18next'
 import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function PdfDownloadFilesButton() {
   const { compiling, fileList } = useCompileContext()
@@ -22,41 +18,19 @@ function PdfDownloadFilesButton() {
   }
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <ControlledDropdown
-          id="dropdown-files-logs-pane"
-          dropup
-          pullRight
-          disabled={compiling || !fileList}
-        >
-          <BS3Dropdown.Toggle
-            className="dropdown-toggle btn-secondary-info btn-secondary"
-            title={t('other_logs_and_files')}
-            bsSize="small"
-            bsStyle={null}
-          />
-          <BS3Dropdown.Menu id="dropdown-files-logs-pane-list">
-            <PdfFileList fileList={fileList} />
-          </BS3Dropdown.Menu>
-        </ControlledDropdown>
-      }
-      bs5={
-        <Dropdown drop="up">
-          <DropdownToggle
-            id="dropdown-files-logs-pane"
-            variant="secondary"
-            size="sm"
-            disabled={compiling || !fileList}
-          >
-            {t('other_logs_and_files')}
-          </DropdownToggle>
-          <DropdownMenu id="dropdown-files-logs-pane-list">
-            <PdfFileList fileList={fileList} />
-          </DropdownMenu>
-        </Dropdown>
-      }
-    />
+    <Dropdown drop="up">
+      <DropdownToggle
+        id="dropdown-files-logs-pane"
+        variant="secondary"
+        size="sm"
+        disabled={compiling || !fileList}
+      >
+        {t('other_logs_and_files')}
+      </DropdownToggle>
+      <DropdownMenu id="dropdown-files-logs-pane-list">
+        <PdfFileList fileList={fileList} />
+      </DropdownMenu>
+    </Dropdown>
   )
 }
 

+ 33 - 87
services/web/frontend/js/features/pdf-preview/components/pdf-file-list.tsx

@@ -1,7 +1,5 @@
-import { MenuItem as BS3MenuItem } from 'react-bootstrap'
 import { useTranslation } from 'react-i18next'
 import { memo } from 'react'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import {
   DropdownDivider,
   DropdownHeader,
@@ -21,94 +19,42 @@ function PdfFileList({ fileList }: { fileList: PdfFileDataList }) {
   }
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <>
-          <BS3MenuItem header>{t('other_output_files')}</BS3MenuItem>
-
-          {fileList.top.map(file => (
-            <BS3MenuItem
-              download={basename(file)}
-              href={file.url}
-              key={file.path}
-            >
-              <b>{file.path}</b>
-            </BS3MenuItem>
-          ))}
-
-          {fileList.other.length > 0 && fileList.top.length > 0 && (
-            <BS3MenuItem divider />
-          )}
-
-          {fileList.other.map(file => (
-            <BS3MenuItem
-              download={basename(file)}
-              href={file.url}
-              key={file.path}
-            >
-              <b>{file.path}</b>
-            </BS3MenuItem>
-          ))}
-
-          {fileList.archive?.fileCount && fileList.archive?.fileCount > 0 && (
-            <BS3MenuItem
+    <>
+      <DropdownHeader>{t('other_output_files')}</DropdownHeader>
+
+      {fileList.top.map(file => (
+        <li key={file.path} role="menuitem">
+          <DropdownItem role="link" download={basename(file)} href={file.url}>
+            {file.path}
+          </DropdownItem>
+        </li>
+      ))}
+
+      {fileList.other.length > 0 && fileList.top.length > 0 && (
+        <DropdownDivider />
+      )}
+
+      {fileList.other.map(file => (
+        <li key={file.path} role="menuitem">
+          <DropdownItem role="link" download={basename(file)} href={file.url}>
+            {file.path}
+          </DropdownItem>
+        </li>
+      ))}
+
+      {fileList.archive?.fileCount !== undefined &&
+        fileList.archive?.fileCount > 0 && (
+          <li role="menuitem">
+            <DropdownItem
+              role="link"
               download={basename(fileList.archive)}
               href={fileList.archive.url}
             >
-              <b>
-                {t('download_all')} ({fileList.archive.fileCount})
-              </b>
-            </BS3MenuItem>
-          )}
-        </>
-      }
-      bs5={
-        <>
-          <DropdownHeader>{t('other_output_files')}</DropdownHeader>
-
-          {fileList.top.map(file => (
-            <li key={file.path} role="menuitem">
-              <DropdownItem
-                role="link"
-                download={basename(file)}
-                href={file.url}
-              >
-                {file.path}
-              </DropdownItem>
-            </li>
-          ))}
-
-          {fileList.other.length > 0 && fileList.top.length > 0 && (
-            <DropdownDivider />
-          )}
-
-          {fileList.other.map(file => (
-            <li key={file.path} role="menuitem">
-              <DropdownItem
-                role="link"
-                download={basename(file)}
-                href={file.url}
-              >
-                {file.path}
-              </DropdownItem>
-            </li>
-          ))}
-
-          {fileList.archive?.fileCount !== undefined &&
-            fileList.archive?.fileCount > 0 && (
-              <li role="menuitem">
-                <DropdownItem
-                  role="link"
-                  download={basename(fileList.archive)}
-                  href={fileList.archive.url}
-                >
-                  {t('download_all')} ({fileList.archive.fileCount})
-                </DropdownItem>
-              </li>
-            )}
-        </>
-      }
-    />
+              {t('download_all')} ({fileList.archive.fileCount})
+            </DropdownItem>
+          </li>
+        )}
+    </>
   )
 }
 

+ 2 - 13
services/web/frontend/js/features/pdf-preview/components/pdf-hybrid-code-check-button.tsx

@@ -1,11 +1,8 @@
 import { memo, useCallback } from 'react'
-import Icon from '../../../shared/components/icon'
 import { useTranslation } from 'react-i18next'
 import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 function PdfHybridCodeCheckButton() {
   const { codeCheckFailed, error, toggleLogs } = useCompileContext()
@@ -27,17 +24,9 @@ function PdfHybridCodeCheckButton() {
       disabled={Boolean(error)}
       className="btn-toggle-logs toolbar-item"
       onClick={handleClick}
-      bs3Props={{
-        bsSize: 'xsmall',
-      }}
     >
-      <BootstrapVersionSwitcher
-        bs3={<Icon type="exclamation-triangle" />}
-        bs5={<MaterialIcon type="warning" />}
-      />
-      <span className={bsVersion({ bs3: 'toolbar-text' })}>
-        {t('code_check_failed')}
-      </span>
+      <MaterialIcon type="warning" />
+      <span className="toolbar-text">{t('code_check_failed')}</span>
     </OLButton>
   )
 }

+ 1 - 6
services/web/frontend/js/features/pdf-preview/components/pdf-hybrid-download-button.tsx

@@ -2,11 +2,9 @@ import { useTranslation } from 'react-i18next'
 import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
 import { useProjectContext } from '@/shared/context/project-context'
 import { sendMB, isSmallDevice } from '@/infrastructure/event-tracking'
-import Icon from '@/shared/components/icon'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function PdfHybridDownloadButton() {
   const { pdfDownloadUrl } = useCompileContext()
@@ -51,10 +49,7 @@ function PdfHybridDownloadButton() {
         style={{ pointerEvents: 'auto' }}
         aria-label={t('download_pdf')}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="download" fw />}
-          bs5={<MaterialIcon type="download" />}
-        />
+        <MaterialIcon type="download" />
       </OLButton>
     </OLTooltip>
   )

+ 1 - 6
services/web/frontend/js/features/pdf-preview/components/pdf-hybrid-logs-button.tsx

@@ -1,13 +1,11 @@
 import { memo, useCallback } from 'react'
 import { useTranslation } from 'react-i18next'
-import Icon from '@/shared/components/icon'
 import MaterialIcon from '@/shared/components/material-icon'
 import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
 import * as eventTracking from '@/infrastructure/event-tracking'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLBadge from '@/features/ui/components/ol/ol-badge'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function PdfHybridLogsButton() {
   const { error, logEntries, toggleLogs, showLogs, stoppedOnFirstError } =
@@ -42,10 +40,7 @@ function PdfHybridLogsButton() {
         style={{ position: 'relative' }}
         aria-label={showLogs ? t('view_pdf') : t('view_logs')}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="file-text-o" fw />}
-          bs5={<MaterialIcon type="description" />}
-        />
+        <MaterialIcon type="description" />
 
         {!showLogs && totalCount > 0 && (
           <OLBadge bg={errorCount === 0 ? 'warning' : 'danger'}>

+ 0 - 4
services/web/frontend/js/features/pdf-preview/components/pdf-log-entry-raw-content.tsx

@@ -49,10 +49,6 @@ export default function PdfLogEntryRawContent({
           <OLButton
             variant="secondary"
             size="sm"
-            bs3Props={{
-              bsSize: 'xsmall',
-              className: 'log-entry-btn-expand-collapse',
-            }}
             onClick={() => setExpanded(value => !value)}
           >
             {expanded ? (

+ 0 - 2
services/web/frontend/js/features/pdf-preview/components/pdf-preview-error.tsx

@@ -25,7 +25,6 @@ function PdfPreviewError({ error }: { error: string }) {
                   <OLButton
                     variant="info"
                     size="sm"
-                    bs3Props={{ bsSize: 'xsmall' }}
                     onClick={() => startCompile()}
                   />,
                 ]}
@@ -284,7 +283,6 @@ function TimedOutLogEntry() {
                   <OLButton
                     variant="info"
                     size="sm"
-                    bs3Props={{ bsSize: 'xsmall' }}
                     onClick={handleEnableStopOnFirstErrorClick}
                   />,
                 ]}

+ 5 - 12
services/web/frontend/js/features/pdf-preview/components/pdf-preview-hybrid-toolbar.tsx

@@ -9,8 +9,6 @@ import PdfHybridDownloadButton from './pdf-hybrid-download-button'
 import PdfHybridCodeCheckButton from './pdf-hybrid-code-check-button'
 import PdfOrphanRefreshButton from './pdf-orphan-refresh-button'
 import { DetachedSynctexControl } from './detach-synctex-control'
-import Icon from '../../../shared/components/icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { Spinner } from 'react-bootstrap-5'
 
 const ORPHAN_UI_TIMEOUT_MS = 5000
@@ -90,16 +88,11 @@ function PdfPreviewHybridToolbarConnectingInner() {
   return (
     <>
       <div className="toolbar-pdf-orphan">
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="refresh" fw spin />}
-          bs5={
-            <Spinner
-              animation="border"
-              aria-hidden="true"
-              size="sm"
-              role="status"
-            />
-          }
+        <Spinner
+          animation="border"
+          aria-hidden="true"
+          size="sm"
+          role="status"
         />
         &nbsp;
         {t('tab_connecting')}…

+ 7 - 56
services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.tsx

@@ -5,7 +5,6 @@ import { getJSON } from '../../../infrastructure/fetch-json'
 import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
 import { useLayoutContext } from '../../../shared/context/layout-context'
 import useScopeValue from '../../../shared/hooks/use-scope-value'
-import Icon from '../../../shared/components/icon'
 import { useTranslation } from 'react-i18next'
 import useIsMounted from '../../../shared/hooks/use-is-mounted'
 import useAbortController from '../../../shared/hooks/use-abort-controller'
@@ -19,10 +18,8 @@ import { debugConsole } from '@/utils/debugging'
 import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import { Spinner } from 'react-bootstrap-5'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
 import useEventListener from '@/shared/hooks/use-event-listener'
 import { PdfScrollPosition } from '@/shared/hooks/use-pdf-scroll-position'
@@ -49,29 +46,11 @@ function GoToCodeButton({
   let buttonIcon = null
   if (syncToCodeInFlight) {
     buttonIcon = (
-      <BootstrapVersionSwitcher
-        bs3={<Icon type="refresh" spin className="synctex-spin-icon" />}
-        bs5={
-          <Spinner
-            animation="border"
-            aria-hidden="true"
-            size="sm"
-            role="status"
-          />
-        }
-      />
+      <Spinner animation="border" aria-hidden="true" size="sm" role="status" />
     )
   } else if (!isDetachLayout) {
     buttonIcon = (
-      <BootstrapVersionSwitcher
-        bs3={<Icon type="arrow-left" className="synctex-control-icon" />}
-        bs5={
-          <MaterialIcon
-            type="arrow_left_alt"
-            className="synctex-control-icon"
-          />
-        }
-      />
+      <MaterialIcon type="arrow_left_alt" className="synctex-control-icon" />
     )
   }
 
@@ -96,9 +75,6 @@ function GoToCodeButton({
         disabled={syncToCodeInFlight}
         className={buttonClasses}
         aria-label={t('go_to_pdf_location_in_code')}
-        bs3Props={{
-          bsSize: 'xsmall',
-        }}
       >
         {buttonIcon}
         {isDetachLayout ? <span>&nbsp;{t('show_in_code')}</span> : ''}
@@ -122,40 +98,18 @@ function GoToPdfButton({
 }) {
   const { t } = useTranslation()
   const tooltipPlacement = isDetachLayout ? 'bottom' : 'right'
-  const buttonClasses = classNames(
-    'synctex-control',
-    bsVersion({ bs3: 'toolbar-btn-secondary' }),
-    {
-      'detach-synctex-control': !!isDetachLayout,
-    }
-  )
+  const buttonClasses = classNames('synctex-control', {
+    'detach-synctex-control': !!isDetachLayout,
+  })
 
   let buttonIcon = null
   if (syncToPdfInFlight) {
     buttonIcon = (
-      <BootstrapVersionSwitcher
-        bs3={<Icon type="refresh" spin className="synctex-spin-icon" />}
-        bs5={
-          <Spinner
-            animation="border"
-            aria-hidden="true"
-            size="sm"
-            role="status"
-          />
-        }
-      />
+      <Spinner animation="border" aria-hidden="true" size="sm" role="status" />
     )
   } else if (!isDetachLayout) {
     buttonIcon = (
-      <BootstrapVersionSwitcher
-        bs3={<Icon type="arrow-right" className="synctex-control-icon" />}
-        bs5={
-          <MaterialIcon
-            type="arrow_right_alt"
-            className="synctex-control-icon"
-          />
-        }
-      />
+      <MaterialIcon type="arrow_right_alt" className="synctex-control-icon" />
     )
   }
 
@@ -172,9 +126,6 @@ function GoToPdfButton({
         disabled={syncToPdfInFlight || !canSyncToPdf}
         className={buttonClasses}
         aria-label={t('go_to_code_location_in_pdf')}
-        bs3Props={{
-          bsSize: 'xsmall',
-        }}
       >
         {buttonIcon}
         {isDetachLayout ? <span>&nbsp;{t('show_in_pdf')}</span> : ''}

+ 109 - 210
services/web/frontend/js/features/pdf-preview/components/pdf-zoom-dropdown.tsx

@@ -1,9 +1,6 @@
-import { Dropdown as BS3Dropdown, MenuItem } from 'react-bootstrap'
 import { useEffect, useState } from 'react'
 import { useTranslation } from 'react-i18next'
-import ControlledDropdown from '@/shared/components/controlled-dropdown'
 import classNames from 'classnames'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import {
   Dropdown,
   DropdownDivider,
@@ -59,215 +56,117 @@ function PdfZoomDropdown({
   const showPresentOption = document.fullscreenEnabled
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <ControlledDropdown
-          id="pdf-zoom-dropdown"
-          onSelect={eventKey => {
-            if (eventKey === 'custom-zoom') {
-              return
-            }
-
-            if (eventKey === 'present') {
-              requestPresentationMode()
-              return
-            }
-
-            setZoom(eventKey)
-          }}
-          pullRight
-        >
-          <BS3Dropdown.Toggle
-            bsStyle={null}
-            className="btn pdf-toolbar-btn pdfjs-zoom-dropdown-button small"
-            value={rawScale}
-            title={rawScaleToPercentage(rawScale)}
-          />
-          <BS3Dropdown.Menu className="pdfjs-zoom-dropdown-menu">
-            <MenuItem
-              draggable={false}
-              disabled
-              className="pdfjs-custom-zoom-menu-item"
-              key="custom-zoom"
-              eventKey="custom-zoom"
-            >
-              <input
-                type="text"
-                onFocus={event => event.target.select()}
-                value={customZoomValue}
-                onKeyDown={event => {
-                  if (event.key === 'Enter') {
-                    const zoom = Number(customZoomValue.replace('%', '')) / 100
-
-                    // Only allow zoom values between 10% and 999%
-                    if (zoom < 0.1) {
-                      setZoom('0.1')
-                    } else if (zoom > 9.99) {
-                      setZoom('9.99')
-                    } else {
-                      setZoom(`${zoom}`)
-                    }
+    <Dropdown
+      onSelect={eventKey => {
+        if (eventKey === 'custom-zoom') {
+          return
+        }
+
+        if (eventKey === 'present') {
+          requestPresentationMode()
+          return
+        }
+
+        setZoom(eventKey)
+      }}
+      align="end"
+    >
+      <DropdownToggle
+        id="pdf-zoom-dropdown"
+        variant="link"
+        className="pdf-toolbar-btn pdfjs-zoom-dropdown-button small"
+      >
+        {rawScaleToPercentage(rawScale)}
+      </DropdownToggle>
+      <DropdownMenu className="pdfjs-zoom-dropdown-menu">
+        <li role="none">
+          <DropdownItem
+            disabled
+            as="div"
+            className="pdfjs-custom-zoom-menu-item"
+            eventKey="custom-zoom"
+          >
+            <FormControl
+              onFocus={event => event.target.select()}
+              value={customZoomValue}
+              onKeyDown={event => {
+                if (event.key === 'Enter') {
+                  const zoom = Number(customZoomValue.replace('%', '')) / 100
+
+                  // Only allow zoom values between 10% and 999%
+                  if (zoom < 0.1) {
+                    setZoom('0.1')
+                  } else if (zoom > 9.99) {
+                    setZoom('9.99')
+                  } else {
+                    setZoom(`${zoom}`)
                   }
-                }}
-                onChange={event => {
-                  const rawValue = event.target.value
-                  const parsedValue = rawValue.replace(/[^0-9%]/g, '')
-                  setCustomZoomValue(parsedValue)
-                }}
-              />
-            </MenuItem>
-            <MenuItem divider />
-            <MenuItem draggable={false} key="zoom-in" eventKey="zoom-in">
-              <span>{t('zoom_in')}</span>
-              <Shortcut keys={shortcuts['zoom-in']} />
-            </MenuItem>
-            <MenuItem draggable={false} key="zoom-out" eventKey="zoom-out">
-              <span>{t('zoom_out')}</span>
-              <Shortcut keys={shortcuts['zoom-out']} />
-            </MenuItem>
-            <MenuItem draggable={false} key="page-width" eventKey="page-width">
-              {t('fit_to_width')}
-              <Shortcut keys={shortcuts['fit-to-width']} />
-            </MenuItem>
-            <MenuItem
-              draggable={false}
-              key="page-height"
-              eventKey="page-height"
-            >
-              {t('fit_to_height')}
-              <Shortcut keys={shortcuts['fit-to-height']} />
-            </MenuItem>
-            {showPresentOption && <MenuItem divider />}
-            {showPresentOption && (
-              <MenuItem draggable={false} key="present" eventKey="present">
-                {t('presentation_mode')}
-              </MenuItem>
-            )}
-            <MenuItem divider />
-            <MenuItem header>{t('zoom_to')}</MenuItem>
-            {zoomValues.map(value => (
-              <MenuItem draggable={false} key={value} eventKey={value}>
-                {rawScaleToPercentage(Number(value))}
-              </MenuItem>
-            ))}
-          </BS3Dropdown.Menu>
-        </ControlledDropdown>
-      }
-      bs5={
-        <Dropdown
-          onSelect={eventKey => {
-            if (eventKey === 'custom-zoom') {
-              return
-            }
-
-            if (eventKey === 'present') {
-              requestPresentationMode()
-              return
-            }
-
-            setZoom(eventKey)
-          }}
-          align="end"
-        >
-          <DropdownToggle
-            id="pdf-zoom-dropdown"
-            variant="link"
-            className="pdf-toolbar-btn pdfjs-zoom-dropdown-button small"
+                }
+              }}
+              onChange={event => {
+                const rawValue = event.target.value
+                const parsedValue = rawValue.replace(/[^0-9%]/g, '')
+                setCustomZoomValue(parsedValue)
+              }}
+            />
+          </DropdownItem>
+        </li>
+        <DropdownDivider />
+        <li role="none">
+          <DropdownItem
+            as="button"
+            eventKey="zoom-in"
+            trailingIcon={<Shortcut keys={shortcuts['zoom-in']} />}
           >
-            {rawScaleToPercentage(rawScale)}
-          </DropdownToggle>
-          <DropdownMenu className="pdfjs-zoom-dropdown-menu">
-            <li role="none">
-              <DropdownItem
-                disabled
-                as="div"
-                className="pdfjs-custom-zoom-menu-item"
-                eventKey="custom-zoom"
-              >
-                <FormControl
-                  onFocus={event => event.target.select()}
-                  value={customZoomValue}
-                  onKeyDown={event => {
-                    if (event.key === 'Enter') {
-                      const zoom =
-                        Number(customZoomValue.replace('%', '')) / 100
-
-                      // Only allow zoom values between 10% and 999%
-                      if (zoom < 0.1) {
-                        setZoom('0.1')
-                      } else if (zoom > 9.99) {
-                        setZoom('9.99')
-                      } else {
-                        setZoom(`${zoom}`)
-                      }
-                    }
-                  }}
-                  onChange={event => {
-                    const rawValue = event.target.value
-                    const parsedValue = rawValue.replace(/[^0-9%]/g, '')
-                    setCustomZoomValue(parsedValue)
-                  }}
-                />
-              </DropdownItem>
-            </li>
-            <DropdownDivider />
-            <li role="none">
-              <DropdownItem
-                as="button"
-                eventKey="zoom-in"
-                trailingIcon={<Shortcut keys={shortcuts['zoom-in']} />}
-              >
-                {t('zoom_in')}
-              </DropdownItem>
-            </li>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                eventKey="zoom-out"
-                trailingIcon={<Shortcut keys={shortcuts['zoom-out']} />}
-              >
-                {t('zoom_out')}
-              </DropdownItem>
-            </li>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                eventKey="page-width"
-                trailingIcon={<Shortcut keys={shortcuts['fit-to-width']} />}
-              >
-                {t('fit_to_width')}
-              </DropdownItem>
-            </li>
-            <li role="none">
-              <DropdownItem
-                as="button"
-                eventKey="page-height"
-                trailingIcon={<Shortcut keys={shortcuts['fit-to-height']} />}
-              >
-                {t('fit_to_height')}
-              </DropdownItem>
-            </li>
-            {showPresentOption && <DropdownDivider />}
-            {showPresentOption && (
-              <li role="none">
-                <DropdownItem as="button" eventKey="present">
-                  {t('presentation_mode')}
-                </DropdownItem>
-              </li>
-            )}
-            <DropdownDivider />
-            <DropdownHeader aria-hidden="true">{t('zoom_to')}</DropdownHeader>
-            {zoomValues.map(value => (
-              <li role="none" key={value}>
-                <DropdownItem as="button" eventKey={value}>
-                  {rawScaleToPercentage(Number(value))}
-                </DropdownItem>
-              </li>
-            ))}
-          </DropdownMenu>
-        </Dropdown>
-      }
-    />
+            {t('zoom_in')}
+          </DropdownItem>
+        </li>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            eventKey="zoom-out"
+            trailingIcon={<Shortcut keys={shortcuts['zoom-out']} />}
+          >
+            {t('zoom_out')}
+          </DropdownItem>
+        </li>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            eventKey="page-width"
+            trailingIcon={<Shortcut keys={shortcuts['fit-to-width']} />}
+          >
+            {t('fit_to_width')}
+          </DropdownItem>
+        </li>
+        <li role="none">
+          <DropdownItem
+            as="button"
+            eventKey="page-height"
+            trailingIcon={<Shortcut keys={shortcuts['fit-to-height']} />}
+          >
+            {t('fit_to_height')}
+          </DropdownItem>
+        </li>
+        {showPresentOption && <DropdownDivider />}
+        {showPresentOption && (
+          <li role="none">
+            <DropdownItem as="button" eventKey="present">
+              {t('presentation_mode')}
+            </DropdownItem>
+          </li>
+        )}
+        <DropdownDivider />
+        <DropdownHeader aria-hidden="true">{t('zoom_to')}</DropdownHeader>
+        {zoomValues.map(value => (
+          <li role="none" key={value}>
+            <DropdownItem as="button" eventKey={value}>
+              {rawScaleToPercentage(Number(value))}
+            </DropdownItem>
+          </li>
+        ))}
+      </DropdownMenu>
+    </Dropdown>
   )
 }
 

+ 1 - 6
services/web/frontend/js/features/pdf-preview/components/stop-on-first-error-prompt.tsx

@@ -28,12 +28,7 @@ export default function StopOnFirstErrorPrompt() {
             // eslint-disable-next-line react/jsx-key
             components={[<strong />]}
           />{' '}
-          <OLButton
-            variant="info"
-            size="sm"
-            onClick={handleDisableButtonClick}
-            bs3Props={{ bsSize: 'xsmall' }}
-          >
+          <OLButton variant="info" size="sm" onClick={handleDisableButtonClick}>
             {t('disable_stop_on_first_error')}
           </OLButton>
         </>

+ 2 - 15
services/web/frontend/js/features/pdf-preview/components/switch-to-editor-button.tsx

@@ -1,8 +1,6 @@
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
 import MaterialIcon from '@/shared/components/material-icon'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { useLayoutContext } from '../../../shared/context/layout-context'
 
 function SwitchToEditorButton() {
@@ -26,19 +24,8 @@ function SwitchToEditorButton() {
   }
 
   return (
-    <OLButton
-      variant="secondary"
-      size="sm"
-      onClick={handleClick}
-      bs3Props={{
-        bsSize: 'xsmall',
-        className: 'switch-to-editor-btn toolbar-btn-secondary',
-      }}
-    >
-      <BootstrapVersionSwitcher
-        bs3={<Icon type="code" className="toolbar-btn-secondary-icon" />}
-        bs5={<MaterialIcon type="code" />}
-      />
+    <OLButton variant="secondary" size="sm" onClick={handleClick}>
+      <MaterialIcon type="code" />
       {t('switch_to_editor')}
     </OLButton>
   )

+ 0 - 1
services/web/frontend/js/features/pdf-preview/components/timeout-upgrade-prompt-new.tsx

@@ -177,7 +177,6 @@ const PreventTimeoutHelpMessage = memo(function PreventTimeoutHelpMessage({
                         className="btn-inline-link fw-bold"
                         size="sm"
                         onClick={handleEnableStopOnFirstErrorClick}
-                        bs3Props={{ bsSize: 'xsmall' }}
                       />,
                       // eslint-disable-next-line react/jsx-key
                       <strong />,

+ 1 - 11
services/web/frontend/js/features/preview/components/preview-log-entry-header.tsx

@@ -3,9 +3,7 @@ import { useState, useRef, MouseEventHandler } from 'react'
 import { useTranslation } from 'react-i18next'
 import useResizeObserver from '../hooks/use-resize-observer'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
-import Icon from '../../../shared/components/icon'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import { ErrorLevel, SourceLocation } from '@/features/pdf-preview/util/types'
 
@@ -91,15 +89,7 @@ function PreviewLogEntryHeader({
       aria-label={headerLogLocationTitle}
       onClick={onSourceLocationClick}
     >
-      <BootstrapVersionSwitcher
-        bs3={
-          <>
-            <Icon type="chain" />
-            &nbsp;
-          </>
-        }
-        bs5={<MaterialIcon type="link" />}
-      />
+      <MaterialIcon type="link" />
       <span ref={logLocationSpanRef} className="log-entry-header-link-location">
         {`\u202A${locationLinkText}\u202C`}
       </span>

+ 2 - 13
services/web/frontend/js/features/preview/components/preview-logs-pane-max-entries.jsx

@@ -3,11 +3,9 @@ import PropTypes from 'prop-types'
 import { Trans, useTranslation } from 'react-i18next'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import PreviewLogEntryHeader from './preview-log-entry-header'
-import Icon from '../../../shared/components/icon'
 import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
 import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-error'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 function PreviewLogsPaneMaxEntries({ totalEntries, entriesShown, hasErrors }) {
   const { t } = useTranslation()
@@ -36,12 +34,7 @@ function PreviewLogsPaneMaxEntries({ totalEntries, entriesShown, hasErrors }) {
           {hasErrors && !stoppedOnFirstError ? (
             <>
               <p>
-                <BootstrapVersionSwitcher
-                  bs3={<Icon type="lightbulb-o" />}
-                  bs5={
-                    <MaterialIcon type="lightbulb" className="align-middle" />
-                  }
-                />
+                <MaterialIcon type="lightbulb" className="align-middle" />
                 &nbsp;
                 <strong>{t('tip')}: </strong>
                 <Trans
@@ -51,7 +44,6 @@ function PreviewLogsPaneMaxEntries({ totalEntries, entriesShown, hasErrors }) {
                       variant="info"
                       size="sm"
                       key="enable-stop-on-first-error"
-                      bs3Props={{ bsSize: 'xsmall' }}
                       onClick={handleEnableStopOnFirstErrorClick}
                     />,
                     // eslint-disable-next-line jsx-a11y/anchor-has-content
@@ -66,10 +58,7 @@ function PreviewLogsPaneMaxEntries({ totalEntries, entriesShown, hasErrors }) {
             </>
           ) : (
             <p>
-              <BootstrapVersionSwitcher
-                bs3={<Icon type="lightbulb-o" />}
-                bs5={<MaterialIcon type="lightbulb" className="align-middle" />}
-              />
+              <MaterialIcon type="lightbulb" className="align-middle" />
               &nbsp;
               <strong>{t('tip')}: </strong>
               {t('log_entry_maximum_entries_see_full_logs')}

+ 29 - 61
services/web/frontend/js/features/review-panel-new/components/review-panel-comment-options.tsx

@@ -1,12 +1,6 @@
-import ControlledDropdown from '@/shared/components/controlled-dropdown'
 import MaterialIcon from '@/shared/components/material-icon'
 import { FC, memo, forwardRef } from 'react'
-import {
-  Dropdown as BS3Dropdown,
-  MenuItem as BS3MenuItem,
-} from 'react-bootstrap'
 import { useTranslation } from 'react-i18next'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import {
   Dropdown,
   DropdownItem,
@@ -38,61 +32,35 @@ const ReviewPanelCommentOptions: FC<{
   }
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <ControlledDropdown id={`review-panel-comment-options-${id}`} pullRight>
-          <BS3Dropdown.Toggle
-            tabIndex={0}
-            noCaret
-            bsSize="small"
-            bsStyle={null}
-          >
-            <MaterialIcon
-              type="more_vert"
-              className="review-panel-entry-actions-icon"
-              accessibilityLabel={t('more_options')}
-            />
-          </BS3Dropdown.Toggle>
-          <BS3Dropdown.Menu>
-            {canEdit && <BS3MenuItem onClick={onEdit}>{t('edit')}</BS3MenuItem>}
-            {canDelete && (
-              <BS3MenuItem onClick={onDelete}>{t('delete')}</BS3MenuItem>
-            )}
-          </BS3Dropdown.Menu>
-        </ControlledDropdown>
-      }
-      bs5={
-        <Dropdown align="end">
-          <DropdownToggle
-            tabIndex={0}
-            as={ReviewPanelCommentDropdownToggleButton}
-            id={`review-panel-comment-options-btn-${id}`}
-          >
-            <MaterialIcon
-              type="more_vert"
-              className="review-panel-entry-actions-icon"
-              accessibilityLabel={t('more_options')}
-            />
-          </DropdownToggle>
-          <DropdownMenu flip={false}>
-            {canEdit && (
-              <li role="none">
-                <DropdownItem as="button" onClick={onEdit}>
-                  {t('edit')}
-                </DropdownItem>
-              </li>
-            )}
-            {canDelete && (
-              <li role="none">
-                <DropdownItem as="button" onClick={onDelete}>
-                  {t('delete')}
-                </DropdownItem>
-              </li>
-            )}
-          </DropdownMenu>
-        </Dropdown>
-      }
-    />
+    <Dropdown align="end">
+      <DropdownToggle
+        tabIndex={0}
+        as={ReviewPanelCommentDropdownToggleButton}
+        id={`review-panel-comment-options-btn-${id}`}
+      >
+        <MaterialIcon
+          type="more_vert"
+          className="review-panel-entry-actions-icon"
+          accessibilityLabel={t('more_options')}
+        />
+      </DropdownToggle>
+      <DropdownMenu flip={false}>
+        {canEdit && (
+          <li role="none">
+            <DropdownItem as="button" onClick={onEdit}>
+              {t('edit')}
+            </DropdownItem>
+          </li>
+        )}
+        {canDelete && (
+          <li role="none">
+            <DropdownItem as="button" onClick={onDelete}>
+              {t('delete')}
+            </DropdownItem>
+          </li>
+        )}
+      </DropdownMenu>
+    </Dropdown>
   )
 }
 

+ 1 - 10
services/web/frontend/js/features/review-panel-new/components/review-panel-more-comments-button.tsx

@@ -3,7 +3,6 @@ import MaterialIcon from '@/shared/components/material-icon'
 import classNames from 'classnames'
 import { useTranslation } from 'react-i18next'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 const MoreCommentsButton: FC<{
   onClick: () => void
@@ -18,15 +17,7 @@ const MoreCommentsButton: FC<{
         upwards: direction === 'upward',
       })}
     >
-      <OLButton
-        variant="secondary"
-        size="sm"
-        className={bsVersion({ bs3: 'review-panel-more-comments-button' })}
-        onClick={onClick}
-        bs3Props={{
-          bsSize: 'xsmall',
-        }}
-      >
+      <OLButton variant="secondary" size="sm" onClick={onClick}>
         <MaterialIcon type={`arrow_${direction}_alt`} />
         {t('more_comments')}
       </OLButton>

+ 1 - 6
services/web/frontend/js/features/review-panel-new/components/review-panel-resolved-threads-button.tsx

@@ -1,11 +1,9 @@
 import React, { FC, useRef, useState } from 'react'
-import Icon from '@/shared/components/icon'
 import OLOverlay from '@/features/ui/components/ol/ol-overlay'
 import OLPopover from '@/features/ui/components/ol/ol-popover'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import { ReviewPanelResolvedThreadsMenu } from './review-panel-resolved-threads-menu'
 import { useTranslation } from 'react-i18next'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import getMeta from '@/utils/meta'
 
@@ -30,10 +28,7 @@ export const ReviewPanelResolvedThreadsButton: FC = () => {
           ref={buttonRef}
           onClick={() => setExpanded(true)}
         >
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="inbox" fw />}
-            bs5={<MaterialIcon type="inbox" />}
-          />
+          <MaterialIcon type="inbox" />
         </button>
       </OLTooltip>
       {expanded && (

+ 1 - 10
services/web/frontend/js/features/review-panel-new/components/review-panel-track-changes-menu-button.tsx

@@ -1,8 +1,6 @@
 import { FC, memo, useState } from 'react'
 import { Trans } from 'react-i18next'
 import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
-import Icon from '@/shared/components/icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import { useProjectContext } from '@/shared/context/project-context'
 import UpgradeTrackChangesModal from '@/features/source-editor/components/review-panel/upgrade-track-changes-modal'
@@ -51,14 +49,7 @@ const ReviewPanelTrackChangesMenuButton: FC<{
             components={{ strong: <strong /> }}
           />
         )}
-        <BootstrapVersionSwitcher
-          bs3={<Icon type={menuExpanded ? 'angle-down' : 'angle-right'} />}
-          bs5={
-            <MaterialIcon
-              type={menuExpanded ? 'expand_more' : 'chevron_right'}
-            />
-          }
-        />
+        <MaterialIcon type={menuExpanded ? 'expand_more' : 'chevron_right'} />
       </button>
 
       <UpgradeTrackChangesModal show={showModal} setShow={setShowModal} />

+ 0 - 3
services/web/frontend/js/features/share-project-modal/components/add-collaborators.jsx

@@ -166,9 +166,6 @@ export default function AddCollaborators({ readOnly }) {
             className="privileges"
             value={privileges}
             onChange={event => setPrivileges(event.target.value)}
-            bs3Props={{
-              bsSize: 'sm',
-            }}
           >
             <option disabled={readOnly} value="readAndWrite">
               {t('can_edit')}

+ 11 - 40
services/web/frontend/js/features/share-project-modal/components/edit-member.tsx

@@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next'
 import { useShareProjectContext } from './share-project-modal'
 import TransferOwnershipModal from './transfer-ownership-modal'
 import { removeMemberFromProject, updateMember } from '../utils/api'
-import Icon from '@/shared/components/icon'
 import { useProjectContext } from '@/shared/context/project-context'
 import { sendMB } from '@/infrastructure/event-tracking'
 import { Select } from '@/shared/components/select'
@@ -15,9 +14,6 @@ import OLButton from '@/features/ui/components/ol/ol-button'
 import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
 import OLCol from '@/features/ui/components/ol/ol-col'
 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'
-import classnames from 'classnames'
 import getMeta from '@/utils/meta'
 import { useUserContext } from '@/shared/context/user-context'
 
@@ -135,7 +131,6 @@ export default function EditMember({
 
   return (
     <form
-      className={bsVersion({ bs3: 'form-horizontal' })}
       id="share-project-form"
       onSubmit={e => {
         e.preventDefault()
@@ -144,35 +139,19 @@ export default function EditMember({
         }
       }}
     >
-      <OLFormGroup
-        className={classnames('project-member', bsVersion({ bs5: 'row' }))}
-      >
+      <OLFormGroup className="project-member row">
         <OLCol xs={7}>
           <div className="project-member-email-icon">
-            <BootstrapVersionSwitcher
-              bs3={
-                <Icon
-                  type={
-                    shouldWarnMember() || member.pendingEditor
-                      ? 'warning'
-                      : 'user'
-                  }
-                  fw
-                />
+            <MaterialIcon
+              type={
+                shouldWarnMember() || member.pendingEditor
+                  ? 'warning'
+                  : 'person'
               }
-              bs5={
-                <MaterialIcon
-                  type={
-                    shouldWarnMember() || member.pendingEditor
-                      ? 'warning'
-                      : 'person'
-                  }
-                  className={
-                    shouldWarnMember() || member.pendingEditor
-                      ? 'project-member-warning'
-                      : undefined
-                  }
-                />
+              className={
+                shouldWarnMember() || member.pendingEditor
+                  ? 'project-member-warning'
+                  : undefined
               }
             />
             <div className="email-warning">
@@ -200,15 +179,7 @@ export default function EditMember({
 
           <div className="project-member-select">
             {hasBeenDowngraded && !confirmRemoval && (
-              <BootstrapVersionSwitcher
-                bs3={<Icon type="warning" fw />}
-                bs5={
-                  <MaterialIcon
-                    type="warning"
-                    className="project-member-warning"
-                  />
-                }
-              />
+              <MaterialIcon type="warning" className="project-member-warning" />
             )}
 
             <SelectPrivilege

+ 2 - 12
services/web/frontend/js/features/share-project-modal/components/invite.jsx

@@ -1,7 +1,6 @@
 import { useCallback } from 'react'
 import PropTypes from 'prop-types'
 import { useShareProjectContext } from './share-project-modal'
-import Icon from '@/shared/components/icon'
 import { useTranslation } from 'react-i18next'
 import MemberPrivileges from './member-privileges'
 import { resendInvite, revokeInvite } from '../utils/api'
@@ -12,9 +11,6 @@ import OLCol from '@/features/ui/components/ol/ol-col'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLButton from '@/features/ui/components/ol/ol-button'
 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'
-import classnames from 'classnames'
 
 export default function Invite({ invite, isProjectOwner }) {
   const { t } = useTranslation()
@@ -123,15 +119,9 @@ function RevokeInvite({ invite }) {
         variant="link"
         onClick={handleClick}
         aria-label={t('revoke')}
-        className={classnames(
-          'btn-inline-link',
-          bsVersion({ bs5: 'text-decoration-none' })
-        )}
+        className="btn-inline-link text-decoration-none"
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="times" />}
-          bs5={<MaterialIcon type="clear" />}
-        />
+        <MaterialIcon type="clear" />
       </OLButton>
     </OLTooltip>
   )

+ 3 - 13
services/web/frontend/js/features/share-project-modal/components/link-sharing.jsx

@@ -1,7 +1,6 @@
 import { useCallback, useState, useEffect } from 'react'
 import PropTypes from 'prop-types'
 import { useTranslation } from 'react-i18next'
-import Icon from '@/shared/components/icon'
 import { useShareProjectContext } from './share-project-modal'
 import { setProjectAccessLevel } from '../utils/api'
 import { CopyToClipboard } from '@/shared/components/copy-to-clipboard'
@@ -17,7 +16,6 @@ import OLRow from '@/features/ui/components/ol/ol-row'
 import OLCol from '@/features/ui/components/ol/ol-col'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 export default function LinkSharing() {
@@ -161,13 +159,8 @@ function TokenBasedSharing({
           className="btn-chevron align-middle"
           onClick={() => setShowLinks(!showLinks)}
         >
-          <BootstrapVersionSwitcher
-            bs3={<Icon type={showLinks ? 'chevron-up' : 'chevron-down'} fw />}
-            bs5={
-              <MaterialIcon
-                type={showLinks ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}
-              />
-            }
+          <MaterialIcon
+            type={showLinks ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}
           />
         </OLButton>
       </OLCol>
@@ -315,10 +308,7 @@ function LinkSharingInfo() {
         target="_blank"
         rel="noopener"
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="question-circle" />}
-          bs5={<MaterialIcon type="help" className="align-middle" />}
-        />
+        <MaterialIcon type="help" className="align-middle" />
       </a>
     </OLTooltip>
   )

+ 1 - 6
services/web/frontend/js/features/share-project-modal/components/owner-info.jsx

@@ -1,9 +1,7 @@
 import { useProjectContext } from '@/shared/context/project-context'
 import { useTranslation } from 'react-i18next'
-import Icon from '@/shared/components/icon'
 import OLRow from '@/features/ui/components/ol/ol-row'
 import OLCol from '@/features/ui/components/ol/ol-col'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 export default function OwnerInfo() {
@@ -14,10 +12,7 @@ export default function OwnerInfo() {
     <OLRow className="project-member">
       <OLCol xs={8}>
         <div className="project-member-email-icon">
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="user" fw />}
-            bs5={<MaterialIcon type="person" />}
-          />
+          <MaterialIcon type="person" />
           <div className="email-warning">{owner?.email}</div>
         </div>
       </OLCol>

+ 29 - 88
services/web/frontend/js/features/share-project-modal/components/select-collaborators.jsx

@@ -5,12 +5,9 @@ import { matchSorter } from 'match-sorter'
 import { useCombobox } from 'downshift'
 import classnames from 'classnames'
 
-import Icon from '@/shared/components/icon'
 import MaterialIcon from '@/shared/components/material-icon'
 import Tag from '@/features/ui/components/bootstrap-5/tag'
 import { DropdownItem } from '@/features/ui/components/bootstrap-5/dropdown-menu'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import { Spinner } from 'react-bootstrap-5'
 
 // Unicode characters in these Unicode groups:
@@ -163,16 +160,11 @@ export default function SelectCollaborators({
           &nbsp;
         </strong>
         {loading && (
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="refresh" spin />}
-            bs5={
-              <Spinner
-                animation="border"
-                aria-hidden="true"
-                size="sm"
-                role="status"
-              />
-            }
+          <Spinner
+            animation="border"
+            aria-hidden="true"
+            size="sm"
+            role="status"
           />
         )}
       </label>
@@ -265,19 +257,12 @@ export default function SelectCollaborators({
           />
         </div>
 
-        <div
-          className={bsVersion({ bs3: classnames({ autocomplete: isOpen }) })}
-        >
+        <div>
           <ul
             {...getMenuProps()}
-            className={classnames(
-              bsVersion({
-                bs3: 'suggestion-list',
-                bs5: classnames('dropdown-menu select-dropdown-menu', {
-                  show: isOpen,
-                }),
-              })
-            )}
+            className={classnames('dropdown-menu select-dropdown-menu', {
+              show: isOpen,
+            })}
           >
             {isOpen &&
               filteredOptions.map((item, index) => (
@@ -310,33 +295,17 @@ SelectCollaborators.propTypes = {
 
 function Option({ selected, item, getItemProps, index }) {
   return (
-    <li
-      className={bsVersion({
-        bs3: classnames('suggestion-item', { selected }),
-      })}
-      {...getItemProps({ item, index })}
-    >
-      <BootstrapVersionSwitcher
-        bs3={
-          <>
-            <Icon type="user" fw />
-            &nbsp;
-            {item.display}
-          </>
-        }
-        bs5={
-          <DropdownItem
-            as="span"
-            role={undefined}
-            leadingIcon="person"
-            className={classnames({
-              active: selected,
-            })}
-          >
-            {item.display}
-          </DropdownItem>
-        }
-      />
+    <li {...getItemProps({ item, index })}>
+      <DropdownItem
+        as="span"
+        role={undefined}
+        leadingIcon="person"
+        className={classnames({
+          active: selected,
+        })}
+      >
+        {item.display}
+      </DropdownItem>
     </li>
   )
 }
@@ -357,8 +326,6 @@ function SelectedItem({
   getSelectedItemProps,
   index,
 }) {
-  const { t } = useTranslation()
-
   const handleClick = useCallback(
     event => {
       event.preventDefault()
@@ -370,41 +337,15 @@ function SelectedItem({
   )
 
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <span
-          className="tag-item"
-          {...getSelectedItemProps({ selectedItem, index })}
-        >
-          <Icon type="user" fw />
-          <span>{selectedItem.display}</span>
-          <button
-            type="button"
-            className="remove-button btn-inline-link"
-            aria-label={t('remove')}
-            onClick={handleClick}
-          >
-            <Icon type="close" fw />
-          </button>
-        </span>
-      }
-      bs5={
-        <Tag
-          prepend={
-            <BootstrapVersionSwitcher
-              bs3={<Icon type="user" fw />}
-              bs5={<MaterialIcon type="person" />}
-            />
-          }
-          closeBtnProps={{
-            onClick: handleClick,
-          }}
-          {...getSelectedItemProps({ selectedItem, index })}
-        >
-          {selectedItem.display}
-        </Tag>
-      }
-    />
+    <Tag
+      prepend={<MaterialIcon type="person" />}
+      closeBtnProps={{
+        onClick: handleClick,
+      }}
+      {...getSelectedItemProps({ selectedItem, index })}
+    >
+      {selectedItem.display}
+    </Tag>
   )
 }
 

+ 6 - 14
services/web/frontend/js/features/share-project-modal/components/share-project-modal-content.tsx

@@ -1,5 +1,4 @@
 import { useTranslation } from 'react-i18next'
-import Icon from '@/shared/components/icon'
 import { useEditorContext } from '@/shared/context/editor-context'
 import { lazy, Suspense } from 'react'
 import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner'
@@ -12,8 +11,6 @@ import OLModal, {
 } from '@/features/ui/components/ol/ol-modal'
 import OLNotification from '@/features/ui/components/ol/ol-notification'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import { Spinner } from 'react-bootstrap-5'
 
 const ReadOnlyTokenLink = lazy(() =>
@@ -70,18 +67,13 @@ export default function ShareProjectModalContent({
       </OLModalBody>
 
       <OLModalFooter>
-        <div className={bsVersion({ bs3: 'pull-left', bs5: 'me-auto' })}>
+        <div className="me-auto">
           {inFlight && (
-            <BootstrapVersionSwitcher
-              bs3={<Icon type="refresh" spin />}
-              bs5={
-                <Spinner
-                  animation="border"
-                  aria-hidden="true"
-                  size="sm"
-                  role="status"
-                />
-              }
+            <Spinner
+              animation="border"
+              aria-hidden="true"
+              size="sm"
+              role="status"
             />
           )}
         </div>

+ 6 - 14
services/web/frontend/js/features/share-project-modal/components/transfer-ownership-modal.jsx

@@ -1,7 +1,6 @@
 import { useState } from 'react'
 import { Trans, useTranslation } from 'react-i18next'
 import PropTypes from 'prop-types'
-import Icon from '@/shared/components/icon'
 import { transferProjectOwnership } from '../utils/api'
 import { useProjectContext } from '@/shared/context/project-context'
 import { useLocation } from '@/shared/hooks/use-location'
@@ -13,8 +12,6 @@ import OLModal, {
 } from '@/features/ui/components/ol/ol-modal'
 import OLNotification from '@/features/ui/components/ol/ol-notification'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import { Spinner } from 'react-bootstrap-5'
 
 export default function TransferOwnershipModal({ member, cancel }) {
@@ -65,18 +62,13 @@ export default function TransferOwnershipModal({ member, cancel }) {
         )}
       </OLModalBody>
       <OLModalFooter>
-        <div className={bsVersion({ bs3: 'pull-left', bs5: 'me-auto' })}>
+        <div className="me-auto">
           {inflight && (
-            <BootstrapVersionSwitcher
-              bs3={<Icon type="refresh" spin />}
-              bs5={
-                <Spinner
-                  animation="border"
-                  aria-hidden="true"
-                  size="sm"
-                  role="status"
-                />
-              }
+            <Spinner
+              animation="border"
+              aria-hidden="true"
+              size="sm"
+              role="status"
             />
           )}
         </div>

+ 1 - 6
services/web/frontend/js/features/share-project-modal/components/view-member.jsx

@@ -1,20 +1,15 @@
 import PropTypes from 'prop-types'
 import MemberPrivileges from './member-privileges'
-import Icon from '@/shared/components/icon'
 import OLRow from '@/features/ui/components/ol/ol-row'
 import OLCol from '@/features/ui/components/ol/ol-col'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 export default function ViewMember({ member }) {
   return (
     <OLRow className="project-member">
       <OLCol xs={8}>
         <div className="project-member-email-icon">
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="user" fw />}
-            bs5={<MaterialIcon type="person" />}
-          />
+          <MaterialIcon type="person" />
           <div className="email-warning">{member.email}</div>
         </div>
       </OLCol>

+ 7 - 34
services/web/frontend/js/features/source-editor/components/codemirror-search-form.tsx

@@ -17,13 +17,11 @@ import {
 } from '@codemirror/search'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import OLButtonGroup from '@/features/ui/components/ol/ol-button-group'
 import OLFormControl from '@/features/ui/components/ol/ol-form-control'
 import OLCloseButton from '@/features/ui/components/ol/ol-close-button'
 import { useTranslation } from 'react-i18next'
-import Icon from '../../../shared/components/icon'
 import classnames from 'classnames'
 import { useUserSettingsContext } from '@/shared/context/user-settings-context'
 import { getStoredSelection, setStoredSelection } from '../extensions/search'
@@ -328,10 +326,7 @@ const CodeMirrorSearchForm: FC = () => {
               htmlFor={withinSelectionId}
               aria-label={t('search_within_selection')}
             >
-              <BootstrapVersionSwitcher
-                bs3={<Icon type="align-left" fw />}
-                bs5={<MaterialIcon type="format_align_left" />}
-              />
+              <MaterialIcon type="format_align_left" />
             </label>
           </OLTooltip>
         </span>
@@ -411,20 +406,9 @@ const CodeMirrorSearchForm: FC = () => {
               size="sm"
               onClick={() => findPrevious(view)}
             >
-              <BootstrapVersionSwitcher
-                bs3={
-                  <Icon
-                    type="chevron-up"
-                    fw
-                    accessibilityLabel={t('search_previous')}
-                  />
-                }
-                bs5={
-                  <MaterialIcon
-                    type="keyboard_arrow_up"
-                    accessibilityLabel={t('search_previous')}
-                  />
-                }
+              <MaterialIcon
+                type="keyboard_arrow_up"
+                accessibilityLabel={t('search_previous')}
               />
             </OLButton>
 
@@ -433,20 +417,9 @@ const CodeMirrorSearchForm: FC = () => {
               size="sm"
               onClick={() => findNext(view)}
             >
-              <BootstrapVersionSwitcher
-                bs3={
-                  <Icon
-                    type="chevron-down"
-                    fw
-                    accessibilityLabel={t('search_next')}
-                  />
-                }
-                bs5={
-                  <MaterialIcon
-                    type="keyboard_arrow_down"
-                    accessibilityLabel={t('search_next')}
-                  />
-                }
+              <MaterialIcon
+                type="keyboard_arrow_down"
+                accessibilityLabel={t('search_next')}
               />
             </OLButton>
           </OLButtonGroup>

+ 2 - 10
services/web/frontend/js/features/source-editor/components/command-tooltip/href-tooltip.tsx

@@ -14,7 +14,6 @@ import {
   ShortTextArgument,
   UrlArgument,
 } from '../../lezer-latex/latex.terms.mjs'
-import Icon from '../../../../shared/components/icon'
 import { EditorState } from '@codemirror/state'
 import { openURL } from '@/features/source-editor/utils/url'
 import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
@@ -22,7 +21,6 @@ import OLFormLabel from '@/features/ui/components/ol/ol-form-label'
 import OLFormControl from '@/features/ui/components/ol/ol-form-control'
 import OLForm from '@/features/ui/components/ol/ol-form'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 export const HrefTooltipContent: FC = () => {
@@ -118,10 +116,7 @@ export const HrefTooltipContent: FC = () => {
           openURL(url)
         }}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="external-link" fw />}
-          bs5={<MaterialIcon type="open_in_new" />}
-        />
+        <MaterialIcon type="open_in_new" />
 
         {t('open_link')}
       </OLButton>
@@ -139,10 +134,7 @@ export const HrefTooltipContent: FC = () => {
             }
           }}
         >
-          <BootstrapVersionSwitcher
-            bs3={<Icon type="chain-broken" fw />}
-            bs5={<MaterialIcon type="link_off" />}
-          />
+          <MaterialIcon type="link_off" />
 
           {t('remove_link')}
         </OLButton>

+ 1 - 6
services/web/frontend/js/features/source-editor/components/command-tooltip/include-tooltip.tsx

@@ -1,8 +1,6 @@
 import { FC } from 'react'
 import { useTranslation } from 'react-i18next'
-import Icon from '@/shared/components/icon'
 import { useIncludedFile } from '@/features/source-editor/hooks/use-included-file'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 import OLButton from '@/features/ui/components/ol/ol-button'
 
@@ -18,10 +16,7 @@ export const IncludeTooltipContent: FC = () => {
         className="ol-cm-command-tooltip-link"
         onClick={openIncludedFile}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="edit" fw />}
-          bs5={<MaterialIcon type="edit" />}
-        />
+        <MaterialIcon type="edit" />
         {t('open_file')}
       </OLButton>
     </div>

+ 1 - 6
services/web/frontend/js/features/source-editor/components/command-tooltip/input-tooltip.tsx

@@ -1,9 +1,7 @@
 import { FC } from 'react'
 import { useTranslation } from 'react-i18next'
-import Icon from '@/shared/components/icon'
 import { useIncludedFile } from '@/features/source-editor/hooks/use-included-file'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 export const InputTooltipContent: FC = () => {
@@ -18,10 +16,7 @@ export const InputTooltipContent: FC = () => {
         className="ol-cm-command-tooltip-link"
         onClick={openIncludedFile}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="edit" fw />}
-          bs5={<MaterialIcon type="edit" />}
-        />
+        <MaterialIcon type="edit" />
         {t('open_file')}
       </OLButton>
     </div>

+ 1 - 6
services/web/frontend/js/features/source-editor/components/command-tooltip/ref-tooltip.tsx

@@ -19,9 +19,7 @@ import {
   TransactionSpec,
 } from '@codemirror/state'
 import { EditorView } from '@codemirror/view'
-import Icon from '../../../../shared/components/icon'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 export const RefTooltipContent: FC = () => {
@@ -47,10 +45,7 @@ export const RefTooltipContent: FC = () => {
           }
         }}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="link" fw />}
-          bs5={<MaterialIcon type="link" />}
-        />
+        <MaterialIcon type="link" />
         {t('open_target')}
       </OLButton>
     </div>

+ 1 - 6
services/web/frontend/js/features/source-editor/components/command-tooltip/url-tooltip.tsx

@@ -6,11 +6,9 @@ import {
   LiteralArgContent,
   UrlArgument,
 } from '../../lezer-latex/latex.terms.mjs'
-import Icon from '../../../../shared/components/icon'
 import { EditorState } from '@codemirror/state'
 import { openURL } from '@/features/source-editor/utils/url'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
 
 export const UrlTooltipContent: FC = () => {
@@ -30,10 +28,7 @@ export const UrlTooltipContent: FC = () => {
           }
         }}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="external-link" fw />}
-          bs5={<MaterialIcon type="open_in_new" />}
-        />
+        <MaterialIcon type="open_in_new" />
         {t('open_link')}
       </OLButton>
     </div>

+ 8 - 32
services/web/frontend/js/features/source-editor/components/figure-modal/figure-modal-footer.tsx

@@ -2,15 +2,11 @@ import {
   FigureModalSource,
   useFigureModalContext,
 } from './figure-modal-context'
-import Icon from '../../../../shared/components/icon'
 import { FC } from 'react'
 import { useTranslation } from 'react-i18next'
 import { sendMB } from '../../../../infrastructure/event-tracking'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from '@/shared/components/material-icon'
-import { bsVersion } from '@/features/utils/bootstrap-5'
-import classnames from 'classnames'
 
 export const FigureModalFooter: FC<{
   onInsert: () => void
@@ -26,7 +22,6 @@ export const FigureModalFooter: FC<{
         {t('cancel')}
       </OLButton>
       <FigureModalAction onInsert={onInsert} onDelete={onDelete} />
-      <BootstrapVersionSwitcher bs3={<div className="clearfix" />} />
     </>
   )
 }
@@ -38,23 +33,12 @@ const HelpToggle = () => {
     return (
       <OLButton
         variant="link"
-        className={classnames(
-          'figure-modal-help-link',
-          bsVersion({ bs3: 'pull-left', bs5: 'me-auto' })
-        )}
+        className="figure-modal-help-link me-auto"
         onClick={() => dispatch({ helpShown: false })}
       >
-        <BootstrapVersionSwitcher
-          bs3={<Icon type="arrow-left" fw />}
-          bs5={
-            <span>
-              <MaterialIcon
-                type="arrow_left_alt"
-                className="align-text-bottom"
-              />
-            </span>
-          }
-        />{' '}
+        <span>
+          <MaterialIcon type="arrow_left_alt" className="align-text-bottom" />
+        </span>{' '}
         {t('back')}
       </OLButton>
     )
@@ -62,20 +46,12 @@ const HelpToggle = () => {
   return (
     <OLButton
       variant="link"
-      className={classnames(
-        'figure-modal-help-link',
-        bsVersion({ bs3: 'pull-left', bs5: 'me-auto' })
-      )}
+      className="figure-modal-help-link me-auto"
       onClick={() => dispatch({ helpShown: true })}
     >
-      <BootstrapVersionSwitcher
-        bs3={<Icon type="question-circle" fw />}
-        bs5={
-          <span>
-            <MaterialIcon type="help" className="align-text-bottom" />
-          </span>
-        }
-      />{' '}
+      <span>
+        <MaterialIcon type="help" className="align-text-bottom" />
+      </span>{' '}
       {t('help')}
     </OLButton>
   )

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff