mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-01 21:31:36 +02:00
Merge pull request #23344 from overleaf/dp-file-tree-toolbar
Update file tree toolbar in new editor GitOrigin-RevId: 11ca678b50e0c525ae60b806dfbc08773b661b7b
This commit is contained in:
@@ -525,6 +525,7 @@
|
||||
"file_or_folder_name_already_exists": "",
|
||||
"file_outline": "",
|
||||
"file_size": "",
|
||||
"file_tree": "",
|
||||
"files_cannot_include_invalid_characters": "",
|
||||
"files_selected": "",
|
||||
"fill_in_our_quick_survey": "",
|
||||
@@ -668,6 +669,7 @@
|
||||
"hide_configuration": "",
|
||||
"hide_deleted_user": "",
|
||||
"hide_document_preamble": "",
|
||||
"hide_file_tree": "",
|
||||
"hide_local_file_contents": "",
|
||||
"hide_outline": "",
|
||||
"history": "",
|
||||
@@ -1462,6 +1464,7 @@
|
||||
"show_all": "",
|
||||
"show_all_projects": "",
|
||||
"show_document_preamble": "",
|
||||
"show_file_tree": "",
|
||||
"show_hotkeys": "",
|
||||
"show_in_code": "",
|
||||
"show_in_pdf": "",
|
||||
|
||||
Binary file not shown.
@@ -1,20 +1,24 @@
|
||||
// @ts-check
|
||||
// Make sure to run the build-unfilled.mjs script after updating this list
|
||||
// to update the font file with the latest icons.
|
||||
// You may need to hard reload your browser window to see the changes.
|
||||
|
||||
export default /** @type {const} */ ([
|
||||
'book_5',
|
||||
'code',
|
||||
'create_new_folder',
|
||||
'description',
|
||||
'forum',
|
||||
'help',
|
||||
'image',
|
||||
'info',
|
||||
'integration_instructions',
|
||||
'note_add',
|
||||
'picture_as_pdf',
|
||||
'rate_review',
|
||||
'report',
|
||||
'settings',
|
||||
'table_chart',
|
||||
'upload_file',
|
||||
'web_asset',
|
||||
])
|
||||
|
||||
@@ -6,6 +6,7 @@ import FileTreeContext from './file-tree-context'
|
||||
import FileTreeDraggablePreviewLayer from './file-tree-draggable-preview-layer'
|
||||
import FileTreeFolderList from './file-tree-folder-list'
|
||||
import FileTreeToolbar from './file-tree-toolbar'
|
||||
import FileTreeToolbarNew from '@/features/ide-redesign/components/file-tree-toolbar'
|
||||
import FileTreeModalDelete from './modals/file-tree-modal-delete'
|
||||
import FileTreeModalCreateFolder from './modals/file-tree-modal-create-folder'
|
||||
import FileTreeModalError from './modals/file-tree-modal-error'
|
||||
@@ -18,6 +19,7 @@ import FileTreeInner from './file-tree-inner'
|
||||
import { useDragLayer } from 'react-dnd'
|
||||
import classnames from 'classnames'
|
||||
import { pathInFolder } from '@/features/file-tree/util/path'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
const FileTreeRoot = React.memo<{
|
||||
onSelect: () => void
|
||||
@@ -41,6 +43,7 @@ const FileTreeRoot = React.memo<{
|
||||
const { _id: projectId } = useProjectContext()
|
||||
const { fileTreeData } = useFileTreeData()
|
||||
const isReady = Boolean(projectId && fileTreeData)
|
||||
const newEditor = useFeatureFlag('editor-redesign')
|
||||
|
||||
useEffect(() => {
|
||||
if (fileTreeContainer) {
|
||||
@@ -97,7 +100,7 @@ const FileTreeRoot = React.memo<{
|
||||
fileTreeContainer={fileTreeContainer}
|
||||
>
|
||||
{isConnected ? null : <div className="disconnected-overlay" />}
|
||||
<FileTreeToolbar />
|
||||
{newEditor ? <FileTreeToolbarNew /> : <FileTreeToolbar />}
|
||||
<FileTreeContextMenu />
|
||||
<FileTreeInner>
|
||||
<FileTreeRootFolder onDelete={onDelete} />
|
||||
|
||||
@@ -30,6 +30,8 @@ const FileTreeOpenContext = createContext<
|
||||
handleFileTreeInit: () => void
|
||||
handleFileTreeSelect: (selectedEntities: FileTreeFindResult[]) => void
|
||||
handleFileTreeDelete: (entity: FileTreeFindResult) => void
|
||||
fileTreeExpanded: boolean
|
||||
toggleFileTreeExpanded: () => void
|
||||
}
|
||||
| undefined
|
||||
>(undefined)
|
||||
@@ -46,6 +48,13 @@ export const FileTreeOpenProvider: FC = ({ children }) => {
|
||||
const [selectedEntityCount, setSelectedEntityCount] = useState(0)
|
||||
const [fileTreeReady, setFileTreeReady] = useState(false)
|
||||
|
||||
// NOTE: Only used in editor redesign
|
||||
const [fileTreeExpanded, setFileTreeExpanded] = useState(true)
|
||||
|
||||
const toggleFileTreeExpanded = useCallback(() => {
|
||||
setFileTreeExpanded(prev => !prev)
|
||||
}, [])
|
||||
|
||||
const handleFileTreeInit = useCallback(() => {
|
||||
setFileTreeReady(true)
|
||||
}, [])
|
||||
@@ -129,6 +138,8 @@ export const FileTreeOpenProvider: FC = ({ children }) => {
|
||||
handleFileTreeInit,
|
||||
handleFileTreeSelect,
|
||||
handleFileTreeDelete,
|
||||
fileTreeExpanded,
|
||||
toggleFileTreeExpanded,
|
||||
}
|
||||
}, [
|
||||
handleFileTreeDelete,
|
||||
@@ -136,6 +147,8 @@ export const FileTreeOpenProvider: FC = ({ children }) => {
|
||||
handleFileTreeSelect,
|
||||
openEntity,
|
||||
selectedEntityCount,
|
||||
fileTreeExpanded,
|
||||
toggleFileTreeExpanded,
|
||||
])
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,35 +3,42 @@ import { FileTree } from '@/features/ide-react/components/file-tree'
|
||||
import { OutlineContainer } from '@/features/outline/components/outline-container'
|
||||
import { VerticalResizeHandle } from '@/features/ide-react/components/resize/vertical-resize-handle'
|
||||
import { useOutlinePane } from '@/features/ide-react/hooks/use-outline-pane'
|
||||
import useCollapsibleFileTree from '../hooks/use-collapsible-file-tree'
|
||||
import classNames from 'classnames'
|
||||
|
||||
function FileTreeOutlinePanel() {
|
||||
const { outlineEnabled, outlinePanelRef } = useOutlinePane()
|
||||
const { fileTreeExpanded, fileTreePanelRef } = useCollapsibleFileTree()
|
||||
|
||||
return (
|
||||
<PanelGroup
|
||||
className="file-tree-outline-panel-group"
|
||||
autoSaveId="ide-redesign-file-tree-outline"
|
||||
direction="vertical"
|
||||
>
|
||||
<Panel
|
||||
className={classNames('file-tree-panel', {
|
||||
'file-tree-panel-collapsed': !fileTreeExpanded,
|
||||
})}
|
||||
defaultSize={50}
|
||||
minSize={25}
|
||||
id="ide-redesign-file-tree"
|
||||
order={1}
|
||||
collapsible
|
||||
ref={fileTreePanelRef}
|
||||
>
|
||||
<FileTree />
|
||||
</Panel>
|
||||
<VerticalResizeHandle
|
||||
hitAreaMargins={{ coarse: 0, fine: 0 }}
|
||||
disabled={!outlineEnabled}
|
||||
disabled={!outlineEnabled || !fileTreeExpanded}
|
||||
/>
|
||||
<Panel
|
||||
className="file-outline-panel"
|
||||
defaultSize={50}
|
||||
maxSize={75}
|
||||
id="ide-redesign-file-outline"
|
||||
order={2}
|
||||
collapsible
|
||||
ref={outlinePanelRef}
|
||||
style={{ minHeight: 36 }} // keep the header visible
|
||||
>
|
||||
<OutlineContainer />
|
||||
</Panel>
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import * as eventTracking from '../../../infrastructure/event-tracking'
|
||||
import { useFileTreeActionable } from '@/features/file-tree/contexts/file-tree-actionable'
|
||||
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
||||
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||
import MaterialIcon, {
|
||||
AvailableUnfilledIcon,
|
||||
} from '@/shared/components/material-icon'
|
||||
import React from 'react'
|
||||
import useCollapsibleFileTree from '../hooks/use-collapsible-file-tree'
|
||||
|
||||
function FileTreeToolbar() {
|
||||
const { t } = useTranslation()
|
||||
const { fileTreeExpanded, toggleFileTreeExpanded } = useCollapsibleFileTree()
|
||||
|
||||
return (
|
||||
<div className="file-tree-toolbar">
|
||||
<button
|
||||
className="file-tree-expand-collapse-button"
|
||||
onClick={toggleFileTreeExpanded}
|
||||
aria-label={
|
||||
fileTreeExpanded ? t('hide_file_tree') : t('show_file_tree')
|
||||
}
|
||||
>
|
||||
<MaterialIcon
|
||||
type={
|
||||
fileTreeExpanded ? 'keyboard_arrow_down' : 'keyboard_arrow_right'
|
||||
}
|
||||
/>
|
||||
<h4>{t('file_tree')}</h4>
|
||||
</button>
|
||||
<FileTreeActionButtons />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FileTreeActionButtons() {
|
||||
const { t } = useTranslation()
|
||||
const { fileTreeReadOnly } = useFileTreeData()
|
||||
|
||||
const {
|
||||
canCreate,
|
||||
startCreatingFolder,
|
||||
startCreatingDocOrFile,
|
||||
startUploadingDocOrFile,
|
||||
} = useFileTreeActionable()
|
||||
|
||||
if (!canCreate || fileTreeReadOnly) return null
|
||||
|
||||
const createWithAnalytics = () => {
|
||||
eventTracking.sendMB('new-file-click', { location: 'toolbar' })
|
||||
startCreatingDocOrFile()
|
||||
}
|
||||
|
||||
const uploadWithAnalytics = () => {
|
||||
eventTracking.sendMB('upload-click', { location: 'toolbar' })
|
||||
startUploadingDocOrFile()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="file-tree-toolbar-action-buttons">
|
||||
<FileTreeActionButton
|
||||
id="new-file"
|
||||
description={t('new_file')}
|
||||
onClick={createWithAnalytics}
|
||||
iconType="note_add"
|
||||
/>
|
||||
<FileTreeActionButton
|
||||
id="new-folder"
|
||||
description={t('new_folder')}
|
||||
onClick={startCreatingFolder}
|
||||
iconType="create_new_folder"
|
||||
/>
|
||||
<FileTreeActionButton
|
||||
id="upload"
|
||||
description={t('upload')}
|
||||
onClick={uploadWithAnalytics}
|
||||
iconType="upload_file"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FileTreeActionButton({
|
||||
id,
|
||||
description,
|
||||
onClick,
|
||||
iconType,
|
||||
}: {
|
||||
id: string
|
||||
description: string
|
||||
onClick: () => void
|
||||
iconType: AvailableUnfilledIcon
|
||||
}) {
|
||||
return (
|
||||
<OLTooltip
|
||||
id={id}
|
||||
description={description}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<button className="btn file-tree-toolbar-action-button" onClick={onClick}>
|
||||
<MaterialIcon
|
||||
unfilled
|
||||
type={iconType}
|
||||
accessibilityLabel={description}
|
||||
/>
|
||||
</button>
|
||||
</OLTooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export default FileTreeToolbar
|
||||
@@ -0,0 +1,12 @@
|
||||
import { ImperativePanelHandle } from 'react-resizable-panels'
|
||||
import { useRef } from 'react'
|
||||
import useCollapsiblePanel from '@/features/ide-react/hooks/use-collapsible-panel'
|
||||
import { useFileTreeOpenContext } from '@/features/ide-react/context/file-tree-open-context'
|
||||
|
||||
export default function useCollapsibleFileTree() {
|
||||
const { fileTreeExpanded, toggleFileTreeExpanded } = useFileTreeOpenContext()
|
||||
const fileTreePanelRef = useRef<ImperativePanelHandle>(null)
|
||||
useCollapsiblePanel(fileTreeExpanded, fileTreePanelRef)
|
||||
|
||||
return { fileTreeExpanded, fileTreePanelRef, toggleFileTreeExpanded }
|
||||
}
|
||||
@@ -35,6 +35,63 @@
|
||||
--file-tree-item-dragging-preview-bg: #{rgb($bg-light-secondary, 0.6)};
|
||||
--file-tree-item-dragging-preview-colour: #{rgb($content-primary, 0.6)};
|
||||
|
||||
.file-tree-outline-panel-group {
|
||||
background-color: var(--file-tree-bg);
|
||||
}
|
||||
|
||||
.file-tree-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 28px;
|
||||
margin: var(--spacing-02);
|
||||
}
|
||||
|
||||
.file-tree-panel {
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.file-tree-panel-collapsed {
|
||||
max-height: 36px;
|
||||
}
|
||||
|
||||
.file-tree-expand-collapse-button {
|
||||
border-radius: var(--border-radius-base);
|
||||
color: var(--outline-content-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
padding: 0 var(--spacing-02);
|
||||
flex-grow: 1;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--file-tree-item-hover-bg);
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: var(--font-size-02);
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.file-tree-toolbar-action-buttons {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.file-tree-toolbar-action-button {
|
||||
padding: var(--spacing-02);
|
||||
border-radius: var(--border-radius-full);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--file-tree-item-hover-bg);
|
||||
}
|
||||
|
||||
.material-symbols {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.file-tree {
|
||||
background-color: var(--file-tree-bg);
|
||||
}
|
||||
@@ -47,6 +104,7 @@
|
||||
border-left: 1px solid
|
||||
color-mix(in srgb, var(--border-primary) 24%, transparent);
|
||||
margin-left: 14px !important;
|
||||
margin-top: 0;
|
||||
|
||||
&.file-tree-list {
|
||||
border-left: none;
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
);
|
||||
--outline-container-color-bg: var(--bg-light-primary);
|
||||
|
||||
.file-outline-panel {
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.outline-pane {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
@@ -701,6 +701,7 @@
|
||||
"file_outline": "File outline",
|
||||
"file_size": "File size",
|
||||
"file_too_large": "File too large",
|
||||
"file_tree": "File tree",
|
||||
"files_cannot_include_invalid_characters": "File name is empty or contains invalid characters",
|
||||
"files_selected": "files selected.",
|
||||
"fill_in_our_quick_survey": "Fill in our quick survey.",
|
||||
@@ -892,6 +893,7 @@
|
||||
"hide_configuration": "Hide configuration",
|
||||
"hide_deleted_user": "Hide deleted users",
|
||||
"hide_document_preamble": "Hide document preamble",
|
||||
"hide_file_tree": "Hide file tree",
|
||||
"hide_local_file_contents": "Hide Local File Contents",
|
||||
"hide_outline": "Hide File outline",
|
||||
"history": "History",
|
||||
@@ -1933,6 +1935,7 @@
|
||||
"show_all": "show all",
|
||||
"show_all_projects": "Show all projects",
|
||||
"show_document_preamble": "Show document preamble",
|
||||
"show_file_tree": "Show file tree",
|
||||
"show_hotkeys": "Show Hotkeys",
|
||||
"show_in_code": "Show in code",
|
||||
"show_in_pdf": "Show in PDF",
|
||||
|
||||
Reference in New Issue
Block a user