mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 14:13:43 +01:00
Merge pull request #24708 from overleaf/mj-rail-element-tooltips
[web] Add tooltips to rail buttons GitOrigin-RevId: 1b75c48f30b593e9e725bcb9658c4c15c9fe6a66
This commit is contained in:
committed by
Copybot
parent
c183176fd3
commit
6207c853ef
@@ -521,6 +521,7 @@
|
|||||||
"error": "",
|
"error": "",
|
||||||
"error_assist": "",
|
"error_assist": "",
|
||||||
"error_assist_to_help_fixing_latex_errors": "",
|
"error_assist_to_help_fixing_latex_errors": "",
|
||||||
|
"error_log": "",
|
||||||
"error_opening_document": "",
|
"error_opening_document": "",
|
||||||
"error_opening_document_detail": "",
|
"error_opening_document_detail": "",
|
||||||
"error_performing_request": "",
|
"error_performing_request": "",
|
||||||
@@ -1394,6 +1395,7 @@
|
|||||||
"reverse_x_sort_order": "",
|
"reverse_x_sort_order": "",
|
||||||
"revert_pending_plan_change": "",
|
"revert_pending_plan_change": "",
|
||||||
"review": "",
|
"review": "",
|
||||||
|
"review_panel": "",
|
||||||
"review_panel_comments_and_track_changes": "",
|
"review_panel_comments_and_track_changes": "",
|
||||||
"review_your_peers_work": "",
|
"review_your_peers_work": "",
|
||||||
"reviewer": "",
|
"reviewer": "",
|
||||||
|
|||||||
@@ -31,58 +31,31 @@ import { RailHelpShowHotkeysModal } from './help/keyboard-shortcuts'
|
|||||||
import { RailHelpContactUsModal } from './help/contact-us'
|
import { RailHelpContactUsModal } from './help/contact-us'
|
||||||
import { HistorySidebar } from '@/features/ide-react/components/history-sidebar'
|
import { HistorySidebar } from '@/features/ide-react/components/history-sidebar'
|
||||||
import DictionarySettingsModal from './settings/editor-settings/dictionary-settings-modal'
|
import DictionarySettingsModal from './settings/editor-settings/dictionary-settings-modal'
|
||||||
|
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||||
|
|
||||||
type RailElement = {
|
type RailElement = {
|
||||||
icon: AvailableUnfilledIcon
|
icon: AvailableUnfilledIcon
|
||||||
key: RailTabKey
|
key: RailTabKey
|
||||||
component: ReactElement
|
component: ReactElement
|
||||||
indicator?: ReactElement
|
indicator?: ReactElement
|
||||||
|
title: string
|
||||||
hide?: boolean
|
hide?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type RailActionButton = {
|
type RailActionButton = {
|
||||||
key: string
|
key: string
|
||||||
icon: AvailableUnfilledIcon
|
icon: AvailableUnfilledIcon
|
||||||
|
title: string
|
||||||
action: () => void
|
action: () => void
|
||||||
}
|
}
|
||||||
type RailDropdown = {
|
type RailDropdown = {
|
||||||
key: string
|
key: string
|
||||||
icon: AvailableUnfilledIcon
|
icon: AvailableUnfilledIcon
|
||||||
|
title: string
|
||||||
dropdown: ReactElement
|
dropdown: ReactElement
|
||||||
}
|
}
|
||||||
type RailAction = RailDropdown | RailActionButton
|
type RailAction = RailDropdown | RailActionButton
|
||||||
|
|
||||||
const RAIL_TABS: RailElement[] = [
|
|
||||||
{
|
|
||||||
key: 'file-tree',
|
|
||||||
icon: 'description',
|
|
||||||
component: <FileTreeOutlinePanel />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'integrations',
|
|
||||||
icon: 'integration_instructions',
|
|
||||||
component: <IntegrationsPanel />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'review-panel',
|
|
||||||
icon: 'rate_review',
|
|
||||||
component: <>Review panel</>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'chat',
|
|
||||||
icon: 'forum',
|
|
||||||
component: <ChatPane />,
|
|
||||||
indicator: <ChatIndicator />,
|
|
||||||
hide: !getMeta('ol-chatEnabled'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'errors',
|
|
||||||
icon: 'report',
|
|
||||||
component: <ErrorPane />,
|
|
||||||
indicator: <ErrorIndicator />,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const RAIL_MODALS: {
|
const RAIL_MODALS: {
|
||||||
key: RailModalKey
|
key: RailModalKey
|
||||||
modalComponentFunction: FC<{ show: boolean }>
|
modalComponentFunction: FC<{ show: boolean }>
|
||||||
@@ -120,20 +93,61 @@ export const RailLayout = () => {
|
|||||||
|
|
||||||
const isHistoryView = view === 'history'
|
const isHistoryView = view === 'history'
|
||||||
|
|
||||||
|
const railTabs: RailElement[] = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
key: 'file-tree',
|
||||||
|
icon: 'description',
|
||||||
|
title: t('file_tree'),
|
||||||
|
component: <FileTreeOutlinePanel />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'integrations',
|
||||||
|
icon: 'integration_instructions',
|
||||||
|
title: t('integrations'),
|
||||||
|
component: <IntegrationsPanel />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'review-panel',
|
||||||
|
icon: 'rate_review',
|
||||||
|
title: t('review_panel'),
|
||||||
|
component: <>Review panel</>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'chat',
|
||||||
|
icon: 'forum',
|
||||||
|
component: <ChatPane />,
|
||||||
|
indicator: <ChatIndicator />,
|
||||||
|
title: t('chat'),
|
||||||
|
hide: !getMeta('ol-chatEnabled'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'errors',
|
||||||
|
icon: 'report',
|
||||||
|
title: t('error_log'),
|
||||||
|
component: <ErrorPane />,
|
||||||
|
indicator: <ErrorIndicator />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[t]
|
||||||
|
)
|
||||||
|
|
||||||
const railActions: RailAction[] = useMemo(
|
const railActions: RailAction[] = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
key: 'support',
|
key: 'support',
|
||||||
icon: 'help',
|
icon: 'help',
|
||||||
|
title: t('help'),
|
||||||
dropdown: <RailHelpDropdown />,
|
dropdown: <RailHelpDropdown />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'settings',
|
key: 'settings',
|
||||||
icon: 'settings',
|
icon: 'settings',
|
||||||
|
title: t('settings'),
|
||||||
action: () => setLeftMenuShown(true),
|
action: () => setLeftMenuShown(true),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[setLeftMenuShown]
|
[setLeftMenuShown, t]
|
||||||
)
|
)
|
||||||
|
|
||||||
const onTabSelect = useCallback(
|
const onTabSelect = useCallback(
|
||||||
@@ -143,7 +157,7 @@ export const RailLayout = () => {
|
|||||||
} else {
|
} else {
|
||||||
// HACK: Apparently the onSelect event is triggered with href attributes
|
// HACK: Apparently the onSelect event is triggered with href attributes
|
||||||
// from DropdownItems
|
// from DropdownItems
|
||||||
if (!RAIL_TABS.some(tab => !tab.hide && tab.key === key)) {
|
if (!railTabs.some(tab => !tab.hide && tab.key === key)) {
|
||||||
// Attempting to open a non-existent tab
|
// Attempting to open a non-existent tab
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -152,7 +166,7 @@ export const RailLayout = () => {
|
|||||||
setIsOpen(true)
|
setIsOpen(true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setSelectedTab, selectedTab, setIsOpen, togglePane]
|
[setSelectedTab, selectedTab, setIsOpen, togglePane, railTabs]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -166,17 +180,18 @@ export const RailLayout = () => {
|
|||||||
>
|
>
|
||||||
<div className={classNames('ide-rail', { hidden: isHistoryView })}>
|
<div className={classNames('ide-rail', { hidden: isHistoryView })}>
|
||||||
<Nav activeKey={selectedTab} className="ide-rail-tabs-nav">
|
<Nav activeKey={selectedTab} className="ide-rail-tabs-nav">
|
||||||
{RAIL_TABS.filter(({ hide }) => !hide).map(
|
{railTabs
|
||||||
({ icon, key, indicator }) => (
|
.filter(({ hide }) => !hide)
|
||||||
|
.map(({ icon, key, indicator, title }) => (
|
||||||
<RailTab
|
<RailTab
|
||||||
open={isOpen && selectedTab === key}
|
open={isOpen && selectedTab === key}
|
||||||
key={key}
|
key={key}
|
||||||
eventKey={key}
|
eventKey={key}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
indicator={indicator}
|
indicator={indicator}
|
||||||
|
title={title}
|
||||||
/>
|
/>
|
||||||
)
|
))}
|
||||||
)}
|
|
||||||
<div className="flex-grow-1" />
|
<div className="flex-grow-1" />
|
||||||
{railActions?.map(action => (
|
{railActions?.map(action => (
|
||||||
<RailActionElement key={action.key} action={action} />
|
<RailActionElement key={action.key} action={action} />
|
||||||
@@ -199,11 +214,13 @@ export const RailLayout = () => {
|
|||||||
className={classNames('ide-rail-content', { hidden: isHistoryView })}
|
className={classNames('ide-rail-content', { hidden: isHistoryView })}
|
||||||
>
|
>
|
||||||
<Tab.Content>
|
<Tab.Content>
|
||||||
{RAIL_TABS.filter(({ hide }) => !hide).map(({ key, component }) => (
|
{railTabs
|
||||||
<Tab.Pane eventKey={key} key={key}>
|
.filter(({ hide }) => !hide)
|
||||||
{component}
|
.map(({ key, component }) => (
|
||||||
</Tab.Pane>
|
<Tab.Pane eventKey={key} key={key}>
|
||||||
))}
|
{component}
|
||||||
|
</Tab.Pane>
|
||||||
|
))}
|
||||||
</Tab.Content>
|
</Tab.Content>
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
@@ -234,26 +251,38 @@ const RailTab = ({
|
|||||||
eventKey,
|
eventKey,
|
||||||
open,
|
open,
|
||||||
indicator,
|
indicator,
|
||||||
|
title,
|
||||||
}: {
|
}: {
|
||||||
icon: AvailableUnfilledIcon
|
icon: AvailableUnfilledIcon
|
||||||
eventKey: string
|
eventKey: string
|
||||||
open: boolean
|
open: boolean
|
||||||
indicator?: ReactElement
|
indicator?: ReactElement
|
||||||
|
title: string
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<NavLink
|
<OLTooltip
|
||||||
eventKey={eventKey}
|
id={`rail-tab-tooltip-${eventKey}`}
|
||||||
className={classNames('ide-rail-tab-link', {
|
description={title}
|
||||||
'open-rail': open,
|
overlayProps={{ delay: 0, placement: 'right' }}
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
{open ? (
|
<NavLink
|
||||||
<MaterialIcon className="ide-rail-tab-link-icon" type={icon} />
|
eventKey={eventKey}
|
||||||
) : (
|
className={classNames('ide-rail-tab-link', {
|
||||||
<MaterialIcon className="ide-rail-tab-link-icon" type={icon} unfilled />
|
'open-rail': open,
|
||||||
)}
|
})}
|
||||||
{indicator}
|
>
|
||||||
</NavLink>
|
{open ? (
|
||||||
|
<MaterialIcon className="ide-rail-tab-link-icon" type={icon} />
|
||||||
|
) : (
|
||||||
|
<MaterialIcon
|
||||||
|
className="ide-rail-tab-link-icon"
|
||||||
|
type={icon}
|
||||||
|
unfilled
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{indicator}
|
||||||
|
</NavLink>
|
||||||
|
</OLTooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,25 +303,39 @@ const RailActionElement = ({ action }: { action: RailAction }) => {
|
|||||||
if ('dropdown' in action) {
|
if ('dropdown' in action) {
|
||||||
return (
|
return (
|
||||||
<Dropdown align="end" drop="end">
|
<Dropdown align="end" drop="end">
|
||||||
<DropdownToggle
|
<OLTooltip
|
||||||
id="rail-help-dropdown-btn"
|
id={`rail-dropdown-tooltip-${action.key}`}
|
||||||
className="ide-rail-tab-link ide-rail-tab-button ide-rail-tab-dropdown"
|
description={action.title}
|
||||||
as="button"
|
overlayProps={{ delay: 0, placement: 'right' }}
|
||||||
>
|
>
|
||||||
{icon}
|
<span>
|
||||||
</DropdownToggle>
|
<DropdownToggle
|
||||||
|
id="rail-help-dropdown-btn"
|
||||||
|
className="ide-rail-tab-link ide-rail-tab-button ide-rail-tab-dropdown"
|
||||||
|
as="button"
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
</DropdownToggle>
|
||||||
|
</span>
|
||||||
|
</OLTooltip>
|
||||||
{action.dropdown}
|
{action.dropdown}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<button
|
<OLTooltip
|
||||||
onClick={onActionClick}
|
id={`rail-tab-tooltip-${action.key}`}
|
||||||
className="ide-rail-tab-link ide-rail-tab-button"
|
description={action.title}
|
||||||
type="button"
|
overlayProps={{ delay: 0, placement: 'right' }}
|
||||||
>
|
>
|
||||||
{icon}
|
<button
|
||||||
</button>
|
onClick={onActionClick}
|
||||||
|
className="ide-rail-tab-link ide-rail-tab-button"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
</button>
|
||||||
|
</OLTooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -673,6 +673,7 @@
|
|||||||
"error": "Error",
|
"error": "Error",
|
||||||
"error_assist": "Error Assist",
|
"error_assist": "Error Assist",
|
||||||
"error_assist_to_help_fixing_latex_errors": "<0>Error Assist</0> for help fixing LaTeX errors",
|
"error_assist_to_help_fixing_latex_errors": "<0>Error Assist</0> for help fixing LaTeX errors",
|
||||||
|
"error_log": "Error log",
|
||||||
"error_opening_document": "Error opening document",
|
"error_opening_document": "Error opening document",
|
||||||
"error_opening_document_detail": "Sorry, something went wrong opening this document. Please try again.",
|
"error_opening_document_detail": "Sorry, something went wrong opening this document. Please try again.",
|
||||||
"error_performing_request": "An error has occurred while performing your request.",
|
"error_performing_request": "An error has occurred while performing your request.",
|
||||||
@@ -1849,6 +1850,7 @@
|
|||||||
"reverse_x_sort_order": "Reverse __x__ sort order",
|
"reverse_x_sort_order": "Reverse __x__ sort order",
|
||||||
"revert_pending_plan_change": "Revert scheduled plan change",
|
"revert_pending_plan_change": "Revert scheduled plan change",
|
||||||
"review": "Review",
|
"review": "Review",
|
||||||
|
"review_panel": "Review panel",
|
||||||
"review_panel_comments_and_track_changes": "Review panel – Comments & track changes",
|
"review_panel_comments_and_track_changes": "Review panel – Comments & track changes",
|
||||||
"review_your_peers_work": "Review your peers’ work",
|
"review_your_peers_work": "Review your peers’ work",
|
||||||
"reviewer": "Reviewer",
|
"reviewer": "Reviewer",
|
||||||
|
|||||||
Reference in New Issue
Block a user