mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-20 15:05:43 +00:00
Merge pull request #24033 from overleaf/mj-rail-dropdown
[web] Editor redesign: Add help dropdown to rail GitOrigin-RevId: 052ba1852a8e2702fe1671c4613d986b9b0c91c2
This commit is contained in:
parent
d7ad742ba3
commit
9824151e62
7 changed files with 162 additions and 14 deletions
|
@ -847,6 +847,7 @@
|
|||
"keep_personal_projects_separate": "",
|
||||
"keep_your_account_safe_add_another_email": "",
|
||||
"keybindings": "",
|
||||
"keyboard_shortcuts": "",
|
||||
"knowledge_base": "",
|
||||
"labels_help_you_to_easily_reference_your_figures": "",
|
||||
"labels_help_you_to_reference_your_tables": "",
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { FC, useCallback } from 'react'
|
||||
import ContactUsModal from '../../../../../../modules/support/frontend/js/components/contact-us-modal'
|
||||
import { useRailContext } from '../../contexts/rail-context'
|
||||
import getMeta from '@/utils/meta'
|
||||
|
||||
export const RailHelpContactUsModal: FC<{ show: boolean }> = ({ show }) => {
|
||||
const { setActiveModal } = useRailContext()
|
||||
const handleHide = useCallback(() => setActiveModal(null), [setActiveModal])
|
||||
const showSupport = getMeta('ol-showSupport')
|
||||
if (!showSupport) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<ContactUsModal show={show} handleHide={handleHide} autofillProjectUrl />
|
||||
)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import { FC } from 'react'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
import HotkeysModal from '@/features/hotkeys-modal/components/hotkeys-modal'
|
||||
import { isMac } from '@/shared/utils/os'
|
||||
import { useRailContext } from '../../contexts/rail-context'
|
||||
|
||||
export const RailHelpShowHotkeysModal: FC<{ show: boolean }> = ({ show }) => {
|
||||
const { features } = useProjectContext()
|
||||
const { setActiveModal } = useRailContext()
|
||||
|
||||
return (
|
||||
<HotkeysModal
|
||||
show={show}
|
||||
handleHide={() => setActiveModal(null)}
|
||||
isMac={isMac}
|
||||
trackChangesVisible={features?.trackChangesVisible}
|
||||
/>
|
||||
)
|
||||
}
|
|
@ -6,7 +6,11 @@ import MaterialIcon, {
|
|||
import { Panel } from 'react-resizable-panels'
|
||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||
import { ErrorIndicator, ErrorPane } from './errors'
|
||||
import { RailTabKey, useRailContext } from '../contexts/rail-context'
|
||||
import {
|
||||
RailModalKey,
|
||||
RailTabKey,
|
||||
useRailContext,
|
||||
} from '../contexts/rail-context'
|
||||
import FileTreeOutlinePanel from './file-tree-outline-panel'
|
||||
import { ChatIndicator, ChatPane } from './chat/chat'
|
||||
import getMeta from '@/utils/meta'
|
||||
|
@ -16,6 +20,15 @@ import { useTranslation } from 'react-i18next'
|
|||
import classNames from 'classnames'
|
||||
import IntegrationsPanel from './integrations-panel/integrations-panel'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownDivider,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownToggle,
|
||||
} from '@/features/ui/components/bootstrap-5/dropdown-menu'
|
||||
import { RailHelpShowHotkeysModal } from './help/keyboard-shortcuts'
|
||||
import { RailHelpContactUsModal } from './help/contact-us'
|
||||
|
||||
type RailElement = {
|
||||
icon: AvailableUnfilledIcon
|
||||
|
@ -25,13 +38,17 @@ type RailElement = {
|
|||
hide?: boolean
|
||||
}
|
||||
|
||||
type RailActionLink = { key: string; icon: AvailableUnfilledIcon; href: string }
|
||||
type RailActionButton = {
|
||||
key: string
|
||||
icon: AvailableUnfilledIcon
|
||||
action: () => void
|
||||
}
|
||||
type RailAction = RailActionLink | RailActionButton
|
||||
type RailDropdown = {
|
||||
key: string
|
||||
icon: AvailableUnfilledIcon
|
||||
dropdown: ReactElement
|
||||
}
|
||||
type RailAction = RailDropdown | RailActionButton
|
||||
|
||||
const RAIL_TABS: RailElement[] = [
|
||||
{
|
||||
|
@ -64,9 +81,24 @@ const RAIL_TABS: RailElement[] = [
|
|||
},
|
||||
]
|
||||
|
||||
const RAIL_MODALS: {
|
||||
key: RailModalKey
|
||||
modalComponentFunction: FC<{ show: boolean }>
|
||||
}[] = [
|
||||
{
|
||||
key: 'keyboard-shortcuts',
|
||||
modalComponentFunction: RailHelpShowHotkeysModal,
|
||||
},
|
||||
{
|
||||
key: 'contact-us',
|
||||
modalComponentFunction: RailHelpContactUsModal,
|
||||
},
|
||||
]
|
||||
|
||||
export const RailLayout = () => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
activeModal,
|
||||
selectedTab,
|
||||
setSelectedTab,
|
||||
isOpen,
|
||||
|
@ -77,11 +109,14 @@ export const RailLayout = () => {
|
|||
togglePane,
|
||||
setResizing,
|
||||
} = useRailContext()
|
||||
|
||||
const { setLeftMenuShown } = useLayoutContext()
|
||||
const railActions: RailAction[] = useMemo(
|
||||
() => [
|
||||
{ key: 'support', icon: 'help', href: '/learn' },
|
||||
{
|
||||
key: 'support',
|
||||
icon: 'help',
|
||||
dropdown: <RailHelpDropdown />,
|
||||
},
|
||||
{
|
||||
key: 'settings',
|
||||
icon: 'settings',
|
||||
|
@ -96,6 +131,12 @@ export const RailLayout = () => {
|
|||
if (key === selectedTab) {
|
||||
togglePane()
|
||||
} else {
|
||||
// HACK: Apparently the onSelect event is triggered with href attributes
|
||||
// from DropdownItems
|
||||
if (!RAIL_TABS.some(tab => !tab.hide && tab.key === key)) {
|
||||
// Attempting to open a non-existent tab
|
||||
return
|
||||
}
|
||||
// Change the selected tab and make sure it's open
|
||||
setSelectedTab((key ?? 'file-tree') as RailTabKey)
|
||||
setIsOpen(true)
|
||||
|
@ -168,6 +209,9 @@ export const RailLayout = () => {
|
|||
tooltipWhenClosed={t('tooltip_show_panel')}
|
||||
/>
|
||||
</HorizontalResizeHandle>
|
||||
{RAIL_MODALS.map(({ key, modalComponentFunction: Component }) => (
|
||||
<Component key={key} show={activeModal === key} />
|
||||
))}
|
||||
</TabContainer>
|
||||
)
|
||||
}
|
||||
|
@ -214,16 +258,18 @@ const RailActionElement = ({ action }: { action: RailAction }) => {
|
|||
}
|
||||
}, [action])
|
||||
|
||||
if ('href' in action) {
|
||||
if ('dropdown' in action) {
|
||||
return (
|
||||
<a
|
||||
href={action.href}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
className="ide-rail-tab-link"
|
||||
>
|
||||
{icon}
|
||||
</a>
|
||||
<Dropdown align="end" drop="end">
|
||||
<DropdownToggle
|
||||
id="rail-help-dropdown-btn"
|
||||
className="ide-rail-tab-link ide-rail-tab-button ide-rail-tab-dropdown"
|
||||
as="button"
|
||||
>
|
||||
{icon}
|
||||
</DropdownToggle>
|
||||
{action.dropdown}
|
||||
</Dropdown>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
|
@ -253,3 +299,44 @@ export const RailPanelHeader: FC<{ title: string }> = ({ title }) => {
|
|||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
const RailHelpDropdown = () => {
|
||||
const showSupport = getMeta('ol-showSupport')
|
||||
const { t } = useTranslation()
|
||||
const { setActiveModal } = useRailContext()
|
||||
const openKeyboardShortcutsModal = useCallback(() => {
|
||||
setActiveModal('keyboard-shortcuts')
|
||||
}, [setActiveModal])
|
||||
const openContactUsModal = useCallback(() => {
|
||||
setActiveModal('contact-us')
|
||||
}, [setActiveModal])
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownItem onClick={openKeyboardShortcutsModal}>
|
||||
{t('keyboard_shortcuts')}
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
href="/learn"
|
||||
role="menuitem"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t('documentation')}
|
||||
</DropdownItem>
|
||||
<DropdownDivider />
|
||||
{showSupport && (
|
||||
<DropdownItem onClick={openContactUsModal}>
|
||||
{t('contact_us')}
|
||||
</DropdownItem>
|
||||
)}
|
||||
<DropdownItem
|
||||
href="https://forms.gle/soyVStc5qDx9na1Z6"
|
||||
role="menuitem"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t('give_feedback')}
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ export type RailTabKey =
|
|||
| 'chat'
|
||||
| 'errors'
|
||||
|
||||
export type RailModalKey = 'keyboard-shortcuts' | 'contact-us'
|
||||
|
||||
const RailContext = createContext<
|
||||
| {
|
||||
selectedTab: RailTabKey
|
||||
|
@ -31,6 +33,8 @@ const RailContext = createContext<
|
|||
handlePaneCollapse: () => void
|
||||
resizing: boolean
|
||||
setResizing: Dispatch<SetStateAction<boolean>>
|
||||
activeModal: RailModalKey | null
|
||||
setActiveModal: Dispatch<SetStateAction<RailModalKey | null>>
|
||||
}
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
@ -38,6 +42,14 @@ const RailContext = createContext<
|
|||
export const RailProvider: FC = ({ children }) => {
|
||||
const [isOpen, setIsOpen] = useState(true)
|
||||
const [resizing, setResizing] = useState(false)
|
||||
const [activeModal, setActiveModalInternal] = useState<RailModalKey | null>(
|
||||
null
|
||||
)
|
||||
const setActiveModal: Dispatch<SetStateAction<RailModalKey | null>> =
|
||||
useCallback(modalKey => {
|
||||
setActiveModalInternal(modalKey)
|
||||
}, [])
|
||||
|
||||
const panelRef = useRef<ImperativePanelHandle>(null)
|
||||
useCollapsiblePanel(isOpen, panelRef)
|
||||
|
||||
|
@ -69,6 +81,8 @@ export const RailProvider: FC = ({ children }) => {
|
|||
handlePaneCollapse,
|
||||
resizing,
|
||||
setResizing,
|
||||
activeModal,
|
||||
setActiveModal,
|
||||
}),
|
||||
[
|
||||
selectedTab,
|
||||
|
@ -81,6 +95,8 @@ export const RailProvider: FC = ({ children }) => {
|
|||
handlePaneCollapse,
|
||||
resizing,
|
||||
setResizing,
|
||||
activeModal,
|
||||
setActiveModal,
|
||||
]
|
||||
)
|
||||
|
||||
|
|
|
@ -133,3 +133,11 @@
|
|||
gap: var(--spacing-02);
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.ide-rail-tab-dropdown {
|
||||
border: 0;
|
||||
|
||||
&.dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1110,6 +1110,7 @@
|
|||
"keep_your_account_safe_add_another_email": "Keep your account safe and make sure you don’t lose access to it by adding another email address.",
|
||||
"keep_your_email_updated": "Keep your email updated so that you don’t lose access to your account and data.",
|
||||
"keybindings": "Keybindings",
|
||||
"keyboard_shortcuts": "Keyboard shortcuts",
|
||||
"knowledge_base": "knowledge base",
|
||||
"ko": "Korean",
|
||||
"labels_help_you_to_easily_reference_your_figures": "Labels help you to easily reference your figures throughout your document. To reference a figure within the text, reference the label using the <0>\\ref{...}</0> command. This makes it easy to reference figures without needing to manually remember the figure numbering. <1>Learn more</1>",
|
||||
|
|
Loading…
Add table
Reference in a new issue