mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #20501 from overleaf/rd-filetree-toolbar
Migrate the file tree toolbar to Bootstrap 5 GitOrigin-RevId: 00ebe585206bf163bf9a00aa56b52d43effd5605
This commit is contained in:
parent
abb59e4603
commit
ac74ba9e8c
8 changed files with 142 additions and 48 deletions
|
@ -1076,6 +1076,7 @@
|
||||||
"progress_bar_percentage": "",
|
"progress_bar_percentage": "",
|
||||||
"project_approaching_file_limit": "",
|
"project_approaching_file_limit": "",
|
||||||
"project_figure_modal": "",
|
"project_figure_modal": "",
|
||||||
|
"project_files": "",
|
||||||
"project_flagged_too_many_compiles": "",
|
"project_flagged_too_many_compiles": "",
|
||||||
"project_has_too_many_files": "",
|
"project_has_too_many_files": "",
|
||||||
"project_last_published_at": "",
|
"project_last_published_at": "",
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import * as eventTracking from '../../../infrastructure/event-tracking'
|
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 Icon from '../../../shared/components/icon'
|
||||||
|
|
||||||
import { useFileTreeActionable } from '../contexts/file-tree-actionable'
|
import { useFileTreeActionable } from '../contexts/file-tree-actionable'
|
||||||
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
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() {
|
function FileTreeToolbar() {
|
||||||
const { fileTreeReadOnly } = useFileTreeData()
|
const { fileTreeReadOnly } = useFileTreeData()
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
if (fileTreeReadOnly) return null
|
if (fileTreeReadOnly) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="toolbar toolbar-filetree">
|
<OLButtonToolbar
|
||||||
|
className="toolbar toolbar-filetree"
|
||||||
|
aria-label={t('project_files')}
|
||||||
|
>
|
||||||
<FileTreeToolbarLeft />
|
<FileTreeToolbarLeft />
|
||||||
<FileTreeToolbarRight />
|
<FileTreeToolbarRight />
|
||||||
</div>
|
</OLButtonToolbar>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,33 +48,54 @@ function FileTreeToolbarLeft() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="toolbar-left">
|
<div className="toolbar-left">
|
||||||
<Tooltip
|
<OLTooltip
|
||||||
id="new-file"
|
id="new-file"
|
||||||
description={t('new_file')}
|
description={t('new_file')}
|
||||||
overlayProps={{ placement: 'bottom' }}
|
overlayProps={{ placement: 'bottom' }}
|
||||||
>
|
>
|
||||||
<Button onClick={createWithAnalytics} bsStyle={null}>
|
<button className="btn" onClick={createWithAnalytics}>
|
||||||
<Icon type="file" fw accessibilityLabel={t('new_file')} />
|
<BootstrapVersionSwitcher
|
||||||
</Button>
|
bs5={
|
||||||
</Tooltip>
|
<MaterialIcon
|
||||||
<Tooltip
|
type="description"
|
||||||
|
accessibilityLabel={t('new_file')}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
bs3={<Icon type="file" fw accessibilityLabel={t('new_file')} />}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</OLTooltip>
|
||||||
|
<OLTooltip
|
||||||
id="new-folder"
|
id="new-folder"
|
||||||
description={t('new_folder')}
|
description={t('new_folder')}
|
||||||
overlayProps={{ placement: 'bottom' }}
|
overlayProps={{ placement: 'bottom' }}
|
||||||
>
|
>
|
||||||
<Button onClick={startCreatingFolder} bsStyle={null}>
|
<button className="btn" onClick={startCreatingFolder} tabIndex={-1}>
|
||||||
<Icon type="folder" fw accessibilityLabel={t('new_folder')} />
|
<BootstrapVersionSwitcher
|
||||||
</Button>
|
bs5={
|
||||||
</Tooltip>
|
<MaterialIcon
|
||||||
<Tooltip
|
type="folder"
|
||||||
|
accessibilityLabel={t('new_folder')}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
bs3={<Icon type="folder" fw accessibilityLabel={t('new_folder')} />}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</OLTooltip>
|
||||||
|
<OLTooltip
|
||||||
id="upload"
|
id="upload"
|
||||||
description={t('upload')}
|
description={t('upload')}
|
||||||
overlayProps={{ placement: 'bottom' }}
|
overlayProps={{ placement: 'bottom' }}
|
||||||
>
|
>
|
||||||
<Button onClick={uploadWithAnalytics}>
|
<button className="btn" onClick={uploadWithAnalytics} tabIndex={-1}>
|
||||||
<Icon type="upload" fw accessibilityLabel={t('upload')} />
|
<BootstrapVersionSwitcher
|
||||||
</Button>
|
bs5={
|
||||||
</Tooltip>
|
<MaterialIcon type="upload" accessibilityLabel={t('upload')} />
|
||||||
|
}
|
||||||
|
bs3={<Icon type="upload" fw accessibilityLabel={t('upload')} />}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</OLTooltip>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -87,26 +112,36 @@ function FileTreeToolbarRight() {
|
||||||
return (
|
return (
|
||||||
<div className="toolbar-right">
|
<div className="toolbar-right">
|
||||||
{canRename ? (
|
{canRename ? (
|
||||||
<Tooltip
|
<OLTooltip
|
||||||
id="rename"
|
id="rename"
|
||||||
description={t('rename')}
|
description={t('rename')}
|
||||||
overlayProps={{ placement: 'bottom' }}
|
overlayProps={{ placement: 'bottom' }}
|
||||||
>
|
>
|
||||||
<Button onClick={startRenaming}>
|
<button className="btn" onClick={startRenaming} tabIndex={-1}>
|
||||||
<Icon type="pencil" fw accessibilityLabel={t('rename')} />
|
<BootstrapVersionSwitcher
|
||||||
</Button>
|
bs3={<Icon type="pencil" fw accessibilityLabel={t('rename')} />}
|
||||||
</Tooltip>
|
bs5={
|
||||||
|
<MaterialIcon type="edit" accessibilityLabel={t('rename')} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</OLTooltip>
|
||||||
) : null}
|
) : null}
|
||||||
{canDelete ? (
|
{canDelete ? (
|
||||||
<Tooltip
|
<OLTooltip
|
||||||
id="delete"
|
id="delete"
|
||||||
description={t('delete')}
|
description={t('delete')}
|
||||||
overlayProps={{ placement: 'bottom' }}
|
overlayProps={{ placement: 'bottom' }}
|
||||||
>
|
>
|
||||||
<Button onClick={startDeleting}>
|
<button className="btn" onClick={startDeleting} tabIndex={-1}>
|
||||||
<Icon type="trash-o" fw accessibilityLabel={t('delete')} />
|
<BootstrapVersionSwitcher
|
||||||
</Button>
|
bs3={<Icon type="trash-o" fw accessibilityLabel={t('delete')} />}
|
||||||
</Tooltip>
|
bs5={
|
||||||
|
<MaterialIcon type="delete" accessibilityLabel={t('delete')} />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</OLTooltip>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import UntrashProjectsButton from './buttons/untrash-projects-button'
|
||||||
import DeleteLeaveProjectsButton from './buttons/delete-leave-projects-button'
|
import DeleteLeaveProjectsButton from './buttons/delete-leave-projects-button'
|
||||||
import LeaveProjectsButton from './buttons/leave-projects-button'
|
import LeaveProjectsButton from './buttons/leave-projects-button'
|
||||||
import DeleteProjectsButton from './buttons/delete-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'
|
import OlButtonGroup from '@/features/ui/components/ol/ol-button-group'
|
||||||
|
|
||||||
function ProjectTools() {
|
function ProjectTools() {
|
||||||
|
@ -19,7 +19,7 @@ function ProjectTools() {
|
||||||
const { filter, selectedProjects } = useProjectListContext()
|
const { filter, selectedProjects } = useProjectListContext()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OlButtonToolbar aria-label={t('toolbar_selected_projects')}>
|
<OLButtonToolbar aria-label={t('toolbar_selected_projects')}>
|
||||||
<OlButtonGroup
|
<OlButtonGroup
|
||||||
aria-label={t('toolbar_selected_projects_management_actions')}
|
aria-label={t('toolbar_selected_projects_management_actions')}
|
||||||
>
|
>
|
||||||
|
@ -48,7 +48,7 @@ function ProjectTools() {
|
||||||
{selectedProjects.length === 1 &&
|
{selectedProjects.length === 1 &&
|
||||||
filter !== 'archived' &&
|
filter !== 'archived' &&
|
||||||
filter !== 'trashed' && <ProjectToolsMoreDropdownButton />}
|
filter !== 'trashed' && <ProjectToolsMoreDropdownButton />}
|
||||||
</OlButtonToolbar>
|
</OLButtonToolbar>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ type OLButtonToolbarProps = ButtonToolbarProps & {
|
||||||
bs3Props?: Record<string, unknown>
|
bs3Props?: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
function OlButtonToolbar(props: OLButtonToolbarProps) {
|
function OLButtonToolbar(props: OLButtonToolbarProps) {
|
||||||
const { bs3Props, ...rest } = props
|
const { bs3Props, ...rest } = props
|
||||||
|
|
||||||
const bs3ButtonToolbarProps: BS3ButtonToolbarProps = {
|
const bs3ButtonToolbarProps: BS3ButtonToolbarProps = {
|
||||||
|
@ -28,4 +28,4 @@ function OlButtonToolbar(props: OLButtonToolbarProps) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default OlButtonToolbar
|
export default OLButtonToolbar
|
||||||
|
|
|
@ -50,14 +50,6 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
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-root,
|
||||||
.file-tree-inner {
|
.file-tree-inner {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
--toolbar-header-btn-border-color: var(--neutral-80);
|
--toolbar-header-btn-border-color: var(--neutral-80);
|
||||||
--toolbar-btn-color: var(--white);
|
--toolbar-btn-color: var(--white);
|
||||||
--toolbar-btn-hover-bg-color: var(--neutral-80);
|
--toolbar-btn-hover-bg-color: var(--neutral-80);
|
||||||
|
--toolbar-btn-hover-color: var(--white);
|
||||||
--project-name-color: var(--neutral-40);
|
--project-name-color: var(--neutral-40);
|
||||||
|
--toolbar-filetree-bg-color: var(--neutral-80);
|
||||||
--project-rename-link-color: var(--neutral-40);
|
--project-rename-link-color: var(--neutral-40);
|
||||||
--project-rename-link-color-hover: var(--neutral-20);
|
--project-rename-link-color-hover: var(--neutral-20);
|
||||||
--editor-header-logo-background: url(../../../../../public/img/ol-brand/overleaf-o-white.svg)
|
--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-header-btn-border-color: var(--neutral-20);
|
||||||
--toolbar-btn-color: var(--neutral-70);
|
--toolbar-btn-color: var(--neutral-70);
|
||||||
--toolbar-btn-hover-bg-color: var(--neutral-10);
|
--toolbar-btn-hover-bg-color: var(--neutral-10);
|
||||||
|
--toolbar-btn-hover-color: var(--neutral-70);
|
||||||
--project-name-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: var(--neutral-70);
|
||||||
--project-rename-link-color-hover: var(--neutral-70);
|
--project-rename-link-color-hover: var(--neutral-70);
|
||||||
--editor-header-logo-background: url(../../../../../public/img/ol-brand/overleaf-o.svg)
|
--editor-header-logo-background: url(../../../../../public/img/ol-brand/overleaf-o.svg)
|
||||||
|
@ -25,10 +29,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
--toolbar-height: 40px;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
align-items: center;
|
||||||
height: var(--toolbar-height);
|
height: var(--toolbar-height);
|
||||||
min-height: var(--toolbar-height);
|
min-height: var(--toolbar-height);
|
||||||
border-bottom: 1px solid var(--toolbar-border-color);
|
border-bottom: 1px solid var(--toolbar-border-color);
|
||||||
|
@ -58,6 +60,59 @@
|
||||||
|
|
||||||
.toolbar-right .back-to-editor-btn {
|
.toolbar-right .back-to-editor-btn {
|
||||||
margin-right: var(--spacing-09);
|
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,
|
a.btn-full-height,
|
||||||
|
@ -140,6 +195,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.toolbar-header {
|
&.toolbar-header {
|
||||||
|
--toolbar-height: 40px;
|
||||||
|
|
||||||
|
align-items: stretch;
|
||||||
background-color: var(--toolbar-header-bg-color);
|
background-color: var(--toolbar-header-bg-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
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 {
|
.editor-menu-icon {
|
||||||
&.material-symbols {
|
&.material-symbols {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
|
|
||||||
// Optional: Group multiple button groups together for a toolbar
|
// Optional: Group multiple button groups together for a toolbar
|
||||||
.btn-toolbar {
|
.btn-toolbar {
|
||||||
margin-left: -5px; // Offset the first child's margin
|
|
||||||
&:extend(.clearfix all);
|
&:extend(.clearfix all);
|
||||||
|
|
||||||
.btn-group,
|
.btn-group,
|
||||||
|
|
|
@ -1541,6 +1541,7 @@
|
||||||
"project": "project",
|
"project": "project",
|
||||||
"project_approaching_file_limit": "This project is approaching the file limit",
|
"project_approaching_file_limit": "This project is approaching the file limit",
|
||||||
"project_figure_modal": "Project",
|
"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_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_has_too_many_files": "This project has reached the 2000 file limit",
|
||||||
"project_last_published_at": "Your project was last published at",
|
"project_last_published_at": "Your project was last published at",
|
||||||
|
|
Loading…
Reference in a new issue