Browse Source

Merge pull request #20501 from overleaf/rd-filetree-toolbar

Migrate the file tree toolbar to Bootstrap 5

GitOrigin-RevId: 00ebe585206bf163bf9a00aa56b52d43effd5605
Rebeka Dekany 2 years ago
parent
commit
ac74ba9e8c

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

@@ -1076,6 +1076,7 @@
   "progress_bar_percentage": "",
   "project_approaching_file_limit": "",
   "project_figure_modal": "",
+  "project_files": "",
   "project_flagged_too_many_compiles": "",
   "project_has_too_many_files": "",
   "project_last_published_at": "",

+ 66 - 31
services/web/frontend/js/features/file-tree/components/file-tree-toolbar.tsx

@@ -1,23 +1,27 @@
 import { useTranslation } from 'react-i18next'
 import * as eventTracking from '../../../infrastructure/event-tracking'
-
-import { Button } from 'react-bootstrap'
-import Tooltip from '../../../shared/components/tooltip'
 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'
 
 function FileTreeToolbar() {
   const { fileTreeReadOnly } = useFileTreeData()
+  const { t } = useTranslation()
 
   if (fileTreeReadOnly) return null
 
   return (
-    <div className="toolbar toolbar-filetree">
+    <OLButtonToolbar
+      className="toolbar toolbar-filetree"
+      aria-label={t('project_files')}
+    >
       <FileTreeToolbarLeft />
       <FileTreeToolbarRight />
-    </div>
+    </OLButtonToolbar>
   )
 }
 
@@ -44,33 +48,54 @@ function FileTreeToolbarLeft() {
 
   return (
     <div className="toolbar-left">
-      <Tooltip
+      <OLTooltip
         id="new-file"
         description={t('new_file')}
         overlayProps={{ placement: 'bottom' }}
       >
-        <Button onClick={createWithAnalytics} bsStyle={null}>
-          <Icon type="file" fw accessibilityLabel={t('new_file')} />
-        </Button>
-      </Tooltip>
-      <Tooltip
+        <button className="btn" onClick={createWithAnalytics}>
+          <BootstrapVersionSwitcher
+            bs5={
+              <MaterialIcon
+                type="description"
+                accessibilityLabel={t('new_file')}
+              />
+            }
+            bs3={<Icon type="file" fw accessibilityLabel={t('new_file')} />}
+          />
+        </button>
+      </OLTooltip>
+      <OLTooltip
         id="new-folder"
         description={t('new_folder')}
         overlayProps={{ placement: 'bottom' }}
       >
-        <Button onClick={startCreatingFolder} bsStyle={null}>
-          <Icon type="folder" fw accessibilityLabel={t('new_folder')} />
-        </Button>
-      </Tooltip>
-      <Tooltip
+        <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')} />}
+          />
+        </button>
+      </OLTooltip>
+      <OLTooltip
         id="upload"
         description={t('upload')}
         overlayProps={{ placement: 'bottom' }}
       >
-        <Button onClick={uploadWithAnalytics}>
-          <Icon type="upload" fw accessibilityLabel={t('upload')} />
-        </Button>
-      </Tooltip>
+        <button className="btn" onClick={uploadWithAnalytics} tabIndex={-1}>
+          <BootstrapVersionSwitcher
+            bs5={
+              <MaterialIcon type="upload" accessibilityLabel={t('upload')} />
+            }
+            bs3={<Icon type="upload" fw accessibilityLabel={t('upload')} />}
+          />
+        </button>
+      </OLTooltip>
     </div>
   )
 }
@@ -87,26 +112,36 @@ function FileTreeToolbarRight() {
   return (
     <div className="toolbar-right">
       {canRename ? (
-        <Tooltip
+        <OLTooltip
           id="rename"
           description={t('rename')}
           overlayProps={{ placement: 'bottom' }}
         >
-          <Button onClick={startRenaming}>
-            <Icon type="pencil" fw accessibilityLabel={t('rename')} />
-          </Button>
-        </Tooltip>
+          <button className="btn" onClick={startRenaming} tabIndex={-1}>
+            <BootstrapVersionSwitcher
+              bs3={<Icon type="pencil" fw accessibilityLabel={t('rename')} />}
+              bs5={
+                <MaterialIcon type="edit" accessibilityLabel={t('rename')} />
+              }
+            />
+          </button>
+        </OLTooltip>
       ) : null}
       {canDelete ? (
-        <Tooltip
+        <OLTooltip
           id="delete"
           description={t('delete')}
           overlayProps={{ placement: 'bottom' }}
         >
-          <Button onClick={startDeleting}>
-            <Icon type="trash-o" fw accessibilityLabel={t('delete')} />
-          </Button>
-        </Tooltip>
+          <button className="btn" onClick={startDeleting} tabIndex={-1}>
+            <BootstrapVersionSwitcher
+              bs3={<Icon type="trash-o" fw accessibilityLabel={t('delete')} />}
+              bs5={
+                <MaterialIcon type="delete" accessibilityLabel={t('delete')} />
+              }
+            />
+          </button>
+        </OLTooltip>
       ) : null}
     </div>
   )

+ 3 - 3
services/web/frontend/js/features/project-list/components/table/project-tools/project-tools.tsx

@@ -11,7 +11,7 @@ import UntrashProjectsButton from './buttons/untrash-projects-button'
 import DeleteLeaveProjectsButton from './buttons/delete-leave-projects-button'
 import LeaveProjectsButton from './buttons/leave-projects-button'
 import DeleteProjectsButton from './buttons/delete-projects-button'
-import OlButtonToolbar from '@/features/ui/components/ol/ol-button-toolbar'
+import OLButtonToolbar from '@/features/ui/components/ol/ol-button-toolbar'
 import OlButtonGroup from '@/features/ui/components/ol/ol-button-group'
 
 function ProjectTools() {
@@ -19,7 +19,7 @@ function ProjectTools() {
   const { filter, selectedProjects } = useProjectListContext()
 
   return (
-    <OlButtonToolbar aria-label={t('toolbar_selected_projects')}>
+    <OLButtonToolbar aria-label={t('toolbar_selected_projects')}>
       <OlButtonGroup
         aria-label={t('toolbar_selected_projects_management_actions')}
       >
@@ -48,7 +48,7 @@ function ProjectTools() {
       {selectedProjects.length === 1 &&
         filter !== 'archived' &&
         filter !== 'trashed' && <ProjectToolsMoreDropdownButton />}
-    </OlButtonToolbar>
+    </OLButtonToolbar>
   )
 }
 

+ 2 - 2
services/web/frontend/js/features/ui/components/ol/ol-button-toolbar.tsx

@@ -10,7 +10,7 @@ type OLButtonToolbarProps = ButtonToolbarProps & {
   bs3Props?: Record<string, unknown>
 }
 
-function OlButtonToolbar(props: OLButtonToolbarProps) {
+function OLButtonToolbar(props: OLButtonToolbarProps) {
   const { bs3Props, ...rest } = props
 
   const bs3ButtonToolbarProps: BS3ButtonToolbarProps = {
@@ -28,4 +28,4 @@ function OlButtonToolbar(props: OLButtonToolbarProps) {
   )
 }
 
-export default OlButtonToolbar
+export default OLButtonToolbar

+ 0 - 8
services/web/frontend/stylesheets/bootstrap-5/pages/editor/file-tree.scss

@@ -50,14 +50,6 @@
   flex-direction: column;
   height: 100%;
 
-  .toolbar.toolbar-filetree {
-    @include toolbar-sm-height;
-    @include toolbar-alt-bg;
-
-    padding: 0 var(--spacing-03);
-    flex-shrink: 0;
-  }
-
   > file-tree-root,
   .file-tree-inner {
     position: relative;

+ 69 - 3
services/web/frontend/stylesheets/bootstrap-5/pages/editor/toolbar.scss

@@ -4,7 +4,9 @@
   --toolbar-header-btn-border-color: var(--neutral-80);
   --toolbar-btn-color: var(--white);
   --toolbar-btn-hover-bg-color: var(--neutral-80);
+  --toolbar-btn-hover-color: var(--white);
   --project-name-color: var(--neutral-40);
+  --toolbar-filetree-bg-color: var(--neutral-80);
   --project-rename-link-color: var(--neutral-40);
   --project-rename-link-color-hover: var(--neutral-20);
   --editor-header-logo-background: url(../../../../../public/img/ol-brand/overleaf-o-white.svg)
@@ -17,7 +19,9 @@
   --toolbar-header-btn-border-color: var(--neutral-20);
   --toolbar-btn-color: var(--neutral-70);
   --toolbar-btn-hover-bg-color: var(--neutral-10);
+  --toolbar-btn-hover-color: var(--neutral-70);
   --project-name-color: var(--neutral-70);
+  --toolbar-filetree-bg-color: var(--white);
   --project-rename-link-color: var(--neutral-70);
   --project-rename-link-color-hover: var(--neutral-70);
   --editor-header-logo-background: url(../../../../../public/img/ol-brand/overleaf-o.svg)
@@ -25,10 +29,8 @@
 }
 
 .toolbar {
-  --toolbar-height: 40px;
-
   display: flex;
-  align-items: stretch;
+  align-items: center;
   height: var(--toolbar-height);
   min-height: var(--toolbar-height);
   border-bottom: 1px solid var(--toolbar-border-color);
@@ -58,6 +60,59 @@
 
   .toolbar-right .back-to-editor-btn {
     margin-right: var(--spacing-09);
+    display: flex;
+    align-items: center;
+
+    .toolbar-label {
+      margin-bottom: 0;
+    }
+  }
+
+  > a:focus,
+  button:focus {
+    outline: none;
+  }
+
+  > a:not(.btn),
+  > button,
+  .toolbar-left > a:not(.btn),
+  .toolbar-left > button,
+  .toolbar-right > a:not(.btn),
+  .toolbar-right > button:not(.back-to-editor-btn) {
+    display: inline-block;
+    color: var(--toolbar-btn-color);
+    background-color: transparent;
+    padding: var(--spacing-01);
+    line-height: 1;
+    height: 24px;
+    border-radius: var(--border-radius-base);
+
+    &.toolbar-header-back-projects {
+      padding: var(--spacing-02) var(--spacing-04) var(--spacing-02);
+      margin-bottom: var(--spacing-01);
+    }
+
+    &:hover {
+      text-shadow: none;
+      color: var(--toolbar-btn-hover-color);
+      background-color: transparent;
+      text-decoration: none;
+    }
+
+    &.active,
+    &:active {
+      .label {
+        display: none;
+      }
+
+      color: white;
+      background-color: var(--bg-info-01);
+      box-shadow: none;
+
+      &:hover {
+        color: white;
+      }
+    }
   }
 
   a.btn-full-height,
@@ -140,6 +195,9 @@
   }
 
   &.toolbar-header {
+    --toolbar-height: 40px;
+
+    align-items: stretch;
     background-color: var(--toolbar-header-bg-color);
     position: absolute;
     top: 0;
@@ -184,6 +242,14 @@
   }
 }
 
+.toolbar-filetree {
+  @include toolbar-sm-height;
+
+  background-color: var(--toolbar-filetree-bg-color);
+  padding: 0 var(--spacing-03);
+  flex-shrink: 0;
+}
+
 .editor-menu-icon {
   &.material-symbols {
     width: 1em;

+ 0 - 1
services/web/frontend/stylesheets/components/button-groups.less

@@ -37,7 +37,6 @@
 
 // Optional: Group multiple button groups together for a toolbar
 .btn-toolbar {
-  margin-left: -5px; // Offset the first child's margin
   &:extend(.clearfix all);
 
   .btn-group,

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

@@ -1541,6 +1541,7 @@
   "project": "project",
   "project_approaching_file_limit": "This project is approaching the file limit",
   "project_figure_modal": "Project",
+  "project_files": "Project files",
   "project_flagged_too_many_compiles": "This project has been flagged for compiling too often. The limit will be lifted shortly.",
   "project_has_too_many_files": "This project has reached the 2000 file limit",
   "project_last_published_at": "Your project was last published at",