first commit

This commit is contained in:
2025-04-24 13:11:28 +08:00
commit ff9c54d5e4
5960 changed files with 834111 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
import { useTranslation } from 'react-i18next'
import { memo, useEffect, useState } from 'react'
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
import OLModal, {
OLModalBody,
OLModalHeader,
OLModalTitle,
} from '@/features/ui/components/ol/ol-modal'
// show modal when editor is forcefully disconnected
function ForceDisconnected() {
const { connectionState } = useConnectionContext()
const { t } = useTranslation()
const [secondsUntilRefresh, setSecondsUntilRefresh] = useState(0)
const [show, setShow] = useState(false)
useEffect(() => {
if (
connectionState.forceDisconnected &&
// out of sync has its own modal
connectionState.error !== 'out-of-sync'
) {
setShow(true)
}
}, [connectionState.forceDisconnected, connectionState.error])
useEffect(() => {
if (connectionState.forceDisconnected) {
setSecondsUntilRefresh(connectionState.forcedDisconnectDelay)
}
}, [connectionState.forceDisconnected, connectionState.forcedDisconnectDelay])
useEffect(() => {
if (show) {
const timer = window.setInterval(() => {
setSecondsUntilRefresh(seconds => Math.max(0, seconds - 1))
}, 1000)
return () => {
window.clearInterval(timer)
}
}
}, [show])
if (!show) {
return null
}
return (
<OLModal
show
// It's not possible to hide this modal, but it's a required prop
onHide={() => {}}
className="lock-editor-modal"
backdrop={false}
keyboard={false}
>
<OLModalHeader>
<OLModalTitle>{t('please_wait')}</OLModalTitle>
</OLModalHeader>
<OLModalBody>
{t('were_performing_maintenance', { seconds: secondsUntilRefresh })}
</OLModalBody>
</OLModal>
)
}
export default memo(ForceDisconnected)

View File

@@ -0,0 +1,53 @@
import { useTranslation } from 'react-i18next'
import { memo } from 'react'
import OLModal, {
OLModalBody,
OLModalFooter,
OLModalHeader,
OLModalTitle,
} from '@/features/ui/components/ol/ol-modal'
import OLButton from '@/features/ui/components/ol/ol-button'
import { ButtonProps } from '@/features/ui/components/types/button-props'
export type GenericConfirmModalOwnProps = {
title: string
message: string
onConfirm: () => void
confirmLabel?: string
primaryVariant?: ButtonProps['variant']
}
type GenericConfirmModalProps = React.ComponentProps<typeof OLModal> &
GenericConfirmModalOwnProps
function GenericConfirmModal({
title,
message,
confirmLabel,
primaryVariant = 'primary',
...modalProps
}: GenericConfirmModalProps) {
const { t } = useTranslation()
const handleConfirmClick = modalProps.onConfirm
return (
<OLModal {...modalProps}>
<OLModalHeader closeButton>
<OLModalTitle>{title}</OLModalTitle>
</OLModalHeader>
<OLModalBody className="modal-generic-confirm">{message}</OLModalBody>
<OLModalFooter>
<OLButton variant="secondary" onClick={() => modalProps.onHide()}>
{t('cancel')}
</OLButton>
<OLButton variant={primaryVariant} onClick={handleConfirmClick}>
{confirmLabel || t('ok')}
</OLButton>
</OLModalFooter>
</OLModal>
)
}
export default memo(GenericConfirmModal)

View File

@@ -0,0 +1,43 @@
import { useTranslation } from 'react-i18next'
import { memo } from 'react'
import OLModal, {
OLModalBody,
OLModalFooter,
OLModalHeader,
OLModalTitle,
} from '@/features/ui/components/ol/ol-modal'
import OLButton from '@/features/ui/components/ol/ol-button'
export type GenericMessageModalOwnProps = {
title: string
message: string
}
type GenericMessageModalProps = React.ComponentProps<typeof OLModal> &
GenericMessageModalOwnProps
function GenericMessageModal({
title,
message,
...modalProps
}: GenericMessageModalProps) {
const { t } = useTranslation()
return (
<OLModal {...modalProps}>
<OLModalHeader closeButton>
<OLModalTitle>{title}</OLModalTitle>
</OLModalHeader>
<OLModalBody className="modal-body-share">{message}</OLModalBody>
<OLModalFooter>
<OLButton variant="secondary" onClick={() => modalProps.onHide()}>
{t('ok')}
</OLButton>
</OLModalFooter>
</OLModal>
)
}
export default memo(GenericMessageModal)

View File

@@ -0,0 +1,17 @@
import { memo } from 'react'
import ForceDisconnected from '@/features/ide-react/components/modals/force-disconnected'
import { UnsavedDocs } from '@/features/ide-react/components/unsaved-docs/unsaved-docs'
import SystemMessages from '@/shared/components/system-messages'
import { IdeRedesignSwitcherModal } from '@/features/ide-redesign/components/switcher-modal/modal'
export const Modals = memo(() => {
return (
<>
<ForceDisconnected />
<UnsavedDocs />
<SystemMessages />
<IdeRedesignSwitcherModal />
</>
)
})
Modals.displayName = 'Modals'

View File

@@ -0,0 +1,86 @@
import { Trans, useTranslation } from 'react-i18next'
import { memo, useState } from 'react'
import { useLocation } from '@/shared/hooks/use-location'
import OLButton from '@/features/ui/components/ol/ol-button'
import OLModal, {
OLModalBody,
OLModalFooter,
OLModalHeader,
OLModalTitle,
} from '@/features/ui/components/ol/ol-modal'
export type OutOfSyncModalProps = {
editorContent: string
show: boolean
onHide: () => void
}
function OutOfSyncModal({ editorContent, show, onHide }: OutOfSyncModalProps) {
const { t } = useTranslation()
const location = useLocation()
const [editorContentShown, setEditorContentShown] = useState(false)
const editorContentRows = (editorContent.match(/\n/g)?.length || 0) + 1
// Reload the page to avoid staying in an inconsistent state.
// https://github.com/overleaf/issues/issues/3694
function done() {
onHide()
location.reload()
}
return (
<OLModal
show={show}
onHide={done}
className="out-of-sync-modal"
backdrop={false}
keyboard={false}
>
<OLModalHeader closeButton>
<OLModalTitle>{t('out_of_sync')}</OLModalTitle>
</OLModalHeader>
<OLModalBody className="modal-body-share">
<Trans
i18nKey="out_of_sync_detail"
components={[
// eslint-disable-next-line react/jsx-key
<br />,
// eslint-disable-next-line jsx-a11y/anchor-has-content,react/jsx-key
<a
target="_blank"
rel="noopener noreferrer"
href="/learn/Kb/Editor_out_of_sync_problems"
/>,
]}
/>
</OLModalBody>
<OLModalBody>
<OLButton
variant="secondary"
onClick={() => setEditorContentShown(shown => !shown)}
>
{editorContentShown
? t('hide_local_file_contents')
: t('show_local_file_contents')}
</OLButton>
{editorContentShown ? (
<div className="text-preview">
<textarea
className="scroll-container"
readOnly
rows={editorContentRows}
value={editorContent}
/>
</div>
) : null}
</OLModalBody>
<OLModalFooter>
<OLButton variant="secondary" onClick={done}>
{t('reload_editor')}
</OLButton>
</OLModalFooter>
</OLModal>
)
}
export default memo(OutOfSyncModal)