mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 06:33:55 +01:00
Merge pull request #32968 from overleaf/worktree-labs-feature-preview
Add labs preview modal to editor GitOrigin-RevId: 0df33135febc8e94129bcdfdfb5c4981326dfab0
This commit is contained in:
+20
-8
@@ -14,6 +14,7 @@ type RailActionButton = {
|
||||
icon: AvailableUnfilledIcon
|
||||
title: string
|
||||
action: () => void
|
||||
indicator?: ReactElement
|
||||
hide?: boolean
|
||||
ref?: React.Ref<HTMLButtonElement>
|
||||
}
|
||||
@@ -23,6 +24,7 @@ type RailDropdown = {
|
||||
icon: AvailableUnfilledIcon
|
||||
title: string
|
||||
dropdown: ReactElement
|
||||
indicator?: ReactElement
|
||||
hide?: boolean
|
||||
ref?: React.Ref<HTMLButtonElement>
|
||||
}
|
||||
@@ -57,10 +59,9 @@ const RailActionElement = forwardRef<HTMLButtonElement, { action: RailAction }>(
|
||||
as="button"
|
||||
aria-label={action.title}
|
||||
>
|
||||
<MaterialIcon
|
||||
className="ide-rail-tab-link-icon"
|
||||
<RailActionIcon
|
||||
type={action.icon}
|
||||
unfilled
|
||||
indicator={action.indicator}
|
||||
/>
|
||||
</DropdownToggle>
|
||||
</span>
|
||||
@@ -81,11 +82,7 @@ const RailActionElement = forwardRef<HTMLButtonElement, { action: RailAction }>(
|
||||
className="ide-rail-tab-link ide-rail-tab-button"
|
||||
aria-label={action.title}
|
||||
>
|
||||
<MaterialIcon
|
||||
className="ide-rail-tab-link-icon"
|
||||
type={action.icon}
|
||||
unfilled
|
||||
/>
|
||||
<RailActionIcon type={action.icon} indicator={action.indicator} />
|
||||
</button>
|
||||
</OLTooltip>
|
||||
)
|
||||
@@ -93,6 +90,21 @@ const RailActionElement = forwardRef<HTMLButtonElement, { action: RailAction }>(
|
||||
}
|
||||
)
|
||||
|
||||
function RailActionIcon({
|
||||
type,
|
||||
indicator,
|
||||
}: {
|
||||
type: AvailableUnfilledIcon
|
||||
indicator?: ReactElement
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<MaterialIcon className="ide-rail-tab-link-icon" type={type} unfilled />
|
||||
{indicator}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
RailActionElement.displayName = 'RailActionElement'
|
||||
|
||||
export default RailActionElement
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import OLBadge from '@/shared/components/ol/ol-badge'
|
||||
|
||||
type RailIndicatorProps = {
|
||||
type: 'danger' | 'warning' | 'info'
|
||||
type: 'danger' | 'warning' | 'info' | 'success'
|
||||
count: number
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,21 @@ import {
|
||||
import { RailHelpContactUsModal } from './contact-us'
|
||||
import { RailHelpShowHotkeysModal } from './keyboard-shortcuts'
|
||||
import DictionarySettingsModal from '@/features/settings/components/editor-settings/dictionary-settings-modal'
|
||||
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
|
||||
|
||||
const RAIL_MODALS: {
|
||||
type RailModalEntry = {
|
||||
key: RailModalKey
|
||||
modalComponentFunction: FC<{ show: boolean }>
|
||||
}[] = [
|
||||
}
|
||||
|
||||
const moduleRailModals = (
|
||||
importOverleafModules('railModals') as {
|
||||
import: { default: RailModalEntry }
|
||||
path: string
|
||||
}[]
|
||||
).map(({ import: { default: entry } }) => entry)
|
||||
|
||||
const RAIL_MODALS: RailModalEntry[] = [
|
||||
{
|
||||
key: 'keyboard-shortcuts',
|
||||
modalComponentFunction: RailHelpShowHotkeysModal,
|
||||
@@ -23,6 +33,7 @@ const RAIL_MODALS: {
|
||||
key: 'dictionary',
|
||||
modalComponentFunction: DictionarySettingsModal,
|
||||
},
|
||||
...moduleRailModals,
|
||||
]
|
||||
|
||||
export default function RailModals() {
|
||||
|
||||
@@ -56,6 +56,13 @@ const moduleRailPopovers = (
|
||||
}[]
|
||||
).map(({ import: { default: element } }) => element)
|
||||
|
||||
const moduleRailActions = (
|
||||
importOverleafModules('railActions') as {
|
||||
import: { default: RailAction }
|
||||
path: string
|
||||
}[]
|
||||
).map(({ import: { default: action } }) => action)
|
||||
|
||||
export const RailLayout = () => {
|
||||
const { sendEvent } = useEditorAnalytics()
|
||||
const { t } = useTranslation()
|
||||
@@ -152,6 +159,7 @@ export const RailLayout = () => {
|
||||
title: t('help'),
|
||||
dropdown: <RailHelpDropdown />,
|
||||
},
|
||||
...moduleRailActions,
|
||||
{
|
||||
key: 'settings',
|
||||
icon: 'settings',
|
||||
|
||||
@@ -25,7 +25,15 @@ export type RailTabKey =
|
||||
| 'full-project-search'
|
||||
| 'workbench'
|
||||
|
||||
export type RailModalKey = 'keyboard-shortcuts' | 'contact-us' | 'dictionary'
|
||||
export type RailModalKey =
|
||||
| 'keyboard-shortcuts'
|
||||
| 'contact-us'
|
||||
| 'dictionary'
|
||||
| 'labs'
|
||||
|
||||
export function dispatchOpenRailModal(key: RailModalKey) {
|
||||
window.dispatchEvent(new CustomEvent('ui:open-rail-modal', { detail: key }))
|
||||
}
|
||||
|
||||
const RailContext = createContext<
|
||||
| {
|
||||
@@ -119,6 +127,16 @@ export const RailProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
}, [handlePaneCollapse, selectedTab, isOpen, openTab])
|
||||
)
|
||||
|
||||
useEventListener(
|
||||
'ui:open-rail-modal',
|
||||
useCallback(
|
||||
(event: Event) => {
|
||||
setActiveModal((event as CustomEvent<RailModalKey>).detail)
|
||||
},
|
||||
[setActiveModal]
|
||||
)
|
||||
)
|
||||
|
||||
useEventListener(
|
||||
'keydown',
|
||||
useCallback(
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
|
||||
type LabsEnableButtonProps = {
|
||||
optedIn: boolean
|
||||
disabled: boolean
|
||||
loading?: boolean
|
||||
ghost?: boolean
|
||||
handleEnable: () => void
|
||||
handleDisable: () => void
|
||||
}
|
||||
|
||||
export function LabsEnableButton({
|
||||
optedIn,
|
||||
disabled,
|
||||
loading,
|
||||
ghost,
|
||||
handleEnable,
|
||||
handleDisable,
|
||||
}: LabsEnableButtonProps) {
|
||||
const { t } = useTranslation()
|
||||
const isDisabled = loading || disabled
|
||||
|
||||
if (optedIn) {
|
||||
return (
|
||||
<OLButton
|
||||
variant={ghost ? 'danger-ghost' : 'secondary'}
|
||||
onClick={handleDisable}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
{t('disable')}
|
||||
</OLButton>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<OLButton
|
||||
variant={ghost ? 'secondary' : 'primary'}
|
||||
onClick={handleEnable}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
{t('enable')}
|
||||
</OLButton>
|
||||
)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { postJSON } from '@/infrastructure/fetch-json'
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
import getMeta from '@/utils/meta'
|
||||
import Notification from '../notification'
|
||||
import { LabsEnableButton } from '@/shared/components/labs/labs-enable-button'
|
||||
|
||||
export type LabsExperimentWidgetProps = {
|
||||
logo: ReactNode
|
||||
@@ -96,11 +97,11 @@ export function LabsExperimentWidget({
|
||||
</div>
|
||||
<div>
|
||||
{labsEnabled && (
|
||||
<ActionButton
|
||||
<LabsEnableButton
|
||||
optedIn={optedIn}
|
||||
handleDisable={handleDisable}
|
||||
handleEnable={handleEnable}
|
||||
disabled={disabled}
|
||||
handleEnable={handleEnable}
|
||||
handleDisable={handleDisable}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -119,40 +120,4 @@ export function LabsExperimentWidget({
|
||||
)
|
||||
}
|
||||
|
||||
type ActionButtonProps = {
|
||||
optedIn?: boolean
|
||||
disabled?: boolean
|
||||
handleEnable: () => void
|
||||
handleDisable: () => void
|
||||
}
|
||||
|
||||
function ActionButton({
|
||||
optedIn,
|
||||
disabled,
|
||||
handleEnable,
|
||||
handleDisable,
|
||||
}: ActionButtonProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
if (optedIn) {
|
||||
return (
|
||||
<OLButton variant="secondary" onClick={handleDisable}>
|
||||
{t('disable')}
|
||||
</OLButton>
|
||||
)
|
||||
} else if (disabled) {
|
||||
return (
|
||||
<OLButton variant="primary" disabled>
|
||||
{t('enable')}
|
||||
</OLButton>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<OLButton variant="primary" onClick={handleEnable}>
|
||||
{t('enable')}
|
||||
</OLButton>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default LabsExperimentWidget
|
||||
|
||||
@@ -206,6 +206,7 @@ export interface Meta {
|
||||
surveyLink: string
|
||||
isFull: boolean
|
||||
optedIn: boolean
|
||||
versionCreatedAt: string | null
|
||||
}>
|
||||
'ol-languages': SpellCheckLanguage[]
|
||||
'ol-learnedWords': string[]
|
||||
|
||||
Reference in New Issue
Block a user