mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-25 10:10:08 +02:00
[web] Editor redesign: Add actions to project name dropdown (#24220)
GitOrigin-RevId: 04f4abdc529a0494c70b0e3d14847b0cf452b80d
This commit is contained in:
committed by
Copybot
parent
0a726ff003
commit
ae4e5b30c1
@@ -427,6 +427,8 @@
|
||||
"dont_reload_or_close_this_tab": "",
|
||||
"download": "",
|
||||
"download_all": "",
|
||||
"download_as_pdf": "",
|
||||
"download_as_source_zip": "",
|
||||
"download_metadata": "",
|
||||
"download_pdf": "",
|
||||
"download_zip_file": "",
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import OLDropdownMenuItem from '@/features/ui/components/ol/ol-dropdown-menu-item'
|
||||
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||
import { isSmallDevice, sendMB } from '@/infrastructure/event-tracking'
|
||||
import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export const DownloadProjectZip = () => {
|
||||
const { t } = useTranslation()
|
||||
const { _id: projectId } = useProjectContext()
|
||||
const sendDownloadEvent = useCallback(() => {
|
||||
sendMB('download-zip-button-click', {
|
||||
projectId,
|
||||
location: 'project-name-dropdown',
|
||||
isSmallDevice,
|
||||
})
|
||||
}, [projectId])
|
||||
|
||||
return (
|
||||
<OLDropdownMenuItem
|
||||
href={`/project/${projectId}/download/zip`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={sendDownloadEvent}
|
||||
>
|
||||
{t('download_as_source_zip')}
|
||||
</OLDropdownMenuItem>
|
||||
)
|
||||
}
|
||||
|
||||
export const DownloadProjectPDF = () => {
|
||||
const { t } = useTranslation()
|
||||
const { pdfDownloadUrl, pdfUrl } = useCompileContext()
|
||||
const { _id: projectId } = useProjectContext()
|
||||
const sendDownloadEvent = useCallback(() => {
|
||||
sendMB('download-pdf-button-click', {
|
||||
projectId,
|
||||
location: 'project-name-dropdown',
|
||||
isSmallDevice,
|
||||
})
|
||||
}, [projectId])
|
||||
|
||||
const button = (
|
||||
<OLDropdownMenuItem
|
||||
href={pdfDownloadUrl || pdfUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
onClick={sendDownloadEvent}
|
||||
disabled={!pdfUrl}
|
||||
>
|
||||
{t('download_as_pdf')}
|
||||
</OLDropdownMenuItem>
|
||||
)
|
||||
|
||||
if (!pdfUrl) {
|
||||
return (
|
||||
<OLTooltip
|
||||
id="tooltip-download-pdf-unavailable"
|
||||
description={t('please_compile_pdf_before_download')}
|
||||
overlayProps={{ placement: 'right', delay: 0 }}
|
||||
>
|
||||
<span>{button}</span>
|
||||
</OLTooltip>
|
||||
)
|
||||
} else {
|
||||
return button
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import OLFormControl from '@/features/ui/components/ol/ol-form-control'
|
||||
import {
|
||||
ChangeEventHandler,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
|
||||
type EditableLabelProps = {
|
||||
initialText: string
|
||||
className?: string
|
||||
onChange: (name: string) => void
|
||||
onCancel: () => void
|
||||
maxLength?: number
|
||||
}
|
||||
|
||||
const EditableLabel = ({
|
||||
initialText,
|
||||
className,
|
||||
onChange,
|
||||
onCancel,
|
||||
maxLength,
|
||||
}: EditableLabelProps) => {
|
||||
const [name, setName] = useState(initialText)
|
||||
|
||||
const inputRef = useRef<HTMLInputElement | null>(null)
|
||||
useEffect(() => {
|
||||
inputRef.current?.select()
|
||||
}, [])
|
||||
|
||||
const onInputChange: ChangeEventHandler<HTMLInputElement> = useCallback(
|
||||
event => {
|
||||
setName(event.target.value)
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const finishRenaming = useCallback(() => {
|
||||
onChange(name)
|
||||
}, [onChange, name])
|
||||
|
||||
const onKeyDown = useCallback(
|
||||
(event: React.KeyboardEvent) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault()
|
||||
finishRenaming()
|
||||
}
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault()
|
||||
onCancel()
|
||||
}
|
||||
},
|
||||
[finishRenaming, onCancel]
|
||||
)
|
||||
|
||||
return (
|
||||
<OLFormControl
|
||||
className={className}
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={onInputChange}
|
||||
onKeyDown={onKeyDown}
|
||||
onBlur={finishRenaming}
|
||||
maxLength={maxLength}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default EditableLabel
|
||||
@@ -4,14 +4,53 @@ import {
|
||||
DropdownMenu,
|
||||
DropdownToggle,
|
||||
} from '@/features/ui/components/bootstrap-5/dropdown-menu'
|
||||
import OLDropdownMenuItem from '@/features/ui/components/ol/ol-dropdown-menu-item'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
|
||||
import { useEditorContext } from '@/shared/context/editor-context'
|
||||
import { DownloadProjectPDF, DownloadProjectZip } from './download-project'
|
||||
import { useCallback, useState } from 'react'
|
||||
import OLDropdownMenuItem from '@/features/ui/components/ol/ol-dropdown-menu-item'
|
||||
import EditableLabel from './editable-label'
|
||||
|
||||
const [publishModalModules] = importOverleafModules('publishModal')
|
||||
const SubmitProjectButton = publishModalModules?.import.NewPublishToolbarButton
|
||||
|
||||
export const ToolbarProjectTitle = () => {
|
||||
const { name } = useProjectContext()
|
||||
const { t } = useTranslation()
|
||||
const { permissionsLevel, renameProject } = useEditorContext()
|
||||
const { name } = useProjectContext()
|
||||
const shouldDisplaySubmitButton =
|
||||
(permissionsLevel === 'owner' || permissionsLevel === 'readAndWrite') &&
|
||||
SubmitProjectButton
|
||||
const hasRenamePermissions = permissionsLevel === 'owner'
|
||||
const [isRenaming, setIsRenaming] = useState(false)
|
||||
const onRename = useCallback(
|
||||
name => {
|
||||
if (name) {
|
||||
renameProject(name)
|
||||
}
|
||||
setIsRenaming(false)
|
||||
},
|
||||
[renameProject]
|
||||
)
|
||||
const onCancel = useCallback(() => {
|
||||
setIsRenaming(false)
|
||||
}, [])
|
||||
|
||||
if (isRenaming) {
|
||||
return (
|
||||
<EditableLabel
|
||||
onChange={onRename}
|
||||
onCancel={onCancel}
|
||||
initialText={name}
|
||||
maxLength={150}
|
||||
className="ide-redesign-toolbar-editable-project-name"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown align="start">
|
||||
<DropdownToggle
|
||||
@@ -24,13 +63,23 @@ export const ToolbarProjectTitle = () => {
|
||||
accessibilityLabel={t('project_title_options')}
|
||||
/>
|
||||
</DropdownToggle>
|
||||
<DropdownMenu>
|
||||
<OLDropdownMenuItem>TODO: Export</OLDropdownMenuItem>
|
||||
<DropdownMenu renderOnMount>
|
||||
{shouldDisplaySubmitButton && (
|
||||
<>
|
||||
<SubmitProjectButton />
|
||||
<DropdownDivider />
|
||||
</>
|
||||
)}
|
||||
<DownloadProjectPDF />
|
||||
<DownloadProjectZip />
|
||||
<DropdownDivider />
|
||||
<OLDropdownMenuItem>{t('rename')}</OLDropdownMenuItem>
|
||||
<OLDropdownMenuItem>{t('download')}</OLDropdownMenuItem>
|
||||
<OLDropdownMenuItem className="text-danger">
|
||||
{t('delete')}
|
||||
<OLDropdownMenuItem
|
||||
onClick={() => {
|
||||
setIsRenaming(true)
|
||||
}}
|
||||
disabled={!hasRenamePermissions}
|
||||
>
|
||||
{t('rename')}
|
||||
</OLDropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
|
||||
@@ -4,14 +4,9 @@ import { ToolbarMenuBar } from './menu-bar'
|
||||
import { ToolbarProjectTitle } from './project-title'
|
||||
import { OnlineUsers } from './online-users'
|
||||
import ShareProjectButton from './share-project-button'
|
||||
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
|
||||
import { useEditorContext } from '@/shared/context/editor-context'
|
||||
import ChangeLayoutButton from './change-layout-button'
|
||||
import ShowHistoryButton from './show-history-button'
|
||||
|
||||
const [publishModalModules] = importOverleafModules('publishModal')
|
||||
const SubmitProjectButton = publishModalModules?.import.NewPublishToolbarButton
|
||||
|
||||
export const Toolbar = () => {
|
||||
return (
|
||||
<div className="ide-redesign-toolbar">
|
||||
@@ -38,18 +33,11 @@ const ToolbarMenus = () => {
|
||||
}
|
||||
|
||||
const ToolbarButtons = () => {
|
||||
const { permissionsLevel } = useEditorContext()
|
||||
|
||||
const shouldDisplaySubmitButton =
|
||||
(permissionsLevel === 'owner' || permissionsLevel === 'readAndWrite') &&
|
||||
SubmitProjectButton
|
||||
|
||||
return (
|
||||
<div className="ide-redesign-toolbar-actions">
|
||||
<OnlineUsers />
|
||||
<ShowHistoryButton />
|
||||
<ChangeLayoutButton />
|
||||
{shouldDisplaySubmitButton && <SubmitProjectButton />}
|
||||
<ShareProjectButton />
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -142,3 +142,10 @@
|
||||
.ide-redesign-online-users {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.ide-redesign-toolbar-editable-project-name {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
margin: var(--spacing-02) 0;
|
||||
}
|
||||
|
||||
@@ -554,6 +554,8 @@
|
||||
"dont_reload_or_close_this_tab": "Don’t reload or close this tab.",
|
||||
"download": "Download",
|
||||
"download_all": "Download all",
|
||||
"download_as_pdf": "Download as PDF",
|
||||
"download_as_source_zip": "Download as source (.zip)",
|
||||
"download_metadata": "Download Overleaf metadata",
|
||||
"download_pdf": "Download PDF",
|
||||
"download_zip_file": "Download .zip file",
|
||||
@@ -587,6 +589,7 @@
|
||||
"dropbox_unlinked_premium_feature": "<0>Your Dropbox account has been unlinked</0> because Dropbox Sync is a premium feature that you had through an institutional license.",
|
||||
"due_date": "Due __date__",
|
||||
"due_today": "Due today",
|
||||
"duplicate": "Duplicate",
|
||||
"duplicate_file": "Duplicate File",
|
||||
"duplicate_projects": "This user has projects with duplicate names",
|
||||
"each_user_will_have_access_to": "Each user will have access to",
|
||||
|
||||
Reference in New Issue
Block a user