Add full project search UI (#22671)

GitOrigin-RevId: f40c85f40f4c16b4b3c26a197924cd9ac9b3db1f
This commit is contained in:
Alf Eaton
2025-01-15 11:22:43 +00:00
committed by Copybot
parent dedb8c48ea
commit 67039e9071
9 changed files with 69 additions and 6 deletions
@@ -333,6 +333,7 @@ const _ProjectController = {
const splitTests = [
!anonymous && 'bib-file-tpr-prompt',
'compile-log-events',
'full-project-search',
'math-preview',
'null-test-share-modal',
'paywall-cta',
+2
View File
@@ -983,6 +983,8 @@ module.exports = {
autoCompleteExtensions: [],
sectionTitleGenerators: [],
toastGenerators: [],
editorSidebarComponents: [],
fileTreeToolbarComponents: [],
},
moduleImportSequence: [
@@ -7,6 +7,12 @@ import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
import MaterialIcon from '@/shared/components/material-icon'
import OLButtonToolbar from '@/features/ui/components/ol/ol-button-toolbar'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import React, { ElementType } from 'react'
const fileTreeToolbarComponents = importOverleafModules(
'fileTreeToolbarComponents'
) as { import: { default: ElementType }; path: string }[]
function FileTreeToolbar() {
const { fileTreeReadOnly } = useFileTreeData()
@@ -105,12 +111,14 @@ function FileTreeToolbarRight() {
const { canRename, canDelete, startRenaming, startDeleting } =
useFileTreeActionable()
if (!canRename && !canDelete) {
return null
}
return (
<div className="toolbar-right">
{fileTreeToolbarComponents.map(
({ import: { default: Component }, path }) => (
<Component key={path} />
)
)}
{canRename ? (
<OLTooltip
id="rename"
@@ -127,6 +135,7 @@ function FileTreeToolbarRight() {
</button>
</OLTooltip>
) : null}
{canDelete ? (
<OLTooltip
id="delete"
@@ -5,6 +5,12 @@ import classNames from 'classnames'
import { useLayoutContext } from '@/shared/context/layout-context'
import { OutlineContainer } from '@/features/outline/components/outline-container'
import { useOutlinePane } from '@/features/ide-react/hooks/use-outline-pane'
import React, { ElementType } from 'react'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
const editorSidebarComponents = importOverleafModules(
'editorSidebarComponents'
) as { import: { default: ElementType }; path: string }[]
export default function EditorSidebar() {
const { view } = useLayoutContext()
@@ -17,6 +23,11 @@ export default function EditorSidebar() {
hidden: view === 'history',
})}
>
{editorSidebarComponents.map(
({ import: { default: Component }, path }) => (
<Component key={path} />
)
)}
<PanelGroup autoSaveId="ide-editor-sidebar-layout" direction="vertical">
<Panel
defaultSize={50}
@@ -7,6 +7,7 @@ import {
Dispatch,
SetStateAction,
FC,
useState,
} from 'react'
import useScopeValue from '../hooks/use-scope-value'
import useDetachLayout from '../hooks/use-detach-layout'
@@ -17,6 +18,7 @@ import { debugConsole } from '@/utils/debugging'
import { BinaryFile } from '@/features/file-view/types/binary-file'
import useScopeEventEmitter from '@/shared/hooks/use-scope-event-emitter'
import useEventListener from '@/shared/hooks/use-event-listener'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
export type IdeLayout = 'sideBySide' | 'flat'
export type IdeView = 'editor' | 'file' | 'pdf' | 'history'
@@ -49,8 +51,12 @@ type LayoutContextValue = {
>
pdfLayout: IdeLayout
pdfPreviewOpen: boolean
projectSearchIsOpen: boolean
setProjectSearchIsOpen: Dispatch<SetStateAction<boolean>>
}
const isMac = /Mac/.test(window.navigator?.platform)
const debugPdfDetach = getMeta('ol-debugPdfDetach')
export const LayoutContext = createContext<LayoutContextValue | undefined>(
@@ -107,6 +113,9 @@ export const LayoutProvider: FC = ({ children }) => {
const [leftMenuShown, setLeftMenuShown] =
useScopeValue<boolean>('ui.leftMenuShown')
// whether the project search is open
const [projectSearchIsOpen, setProjectSearchIsOpen] = useState(false)
useEventListener(
'ui.toggle-left-menu',
useCallback(
@@ -124,6 +133,21 @@ export const LayoutProvider: FC = ({ children }) => {
}, [setReviewPanelOpen])
)
useEventListener(
'keydown',
useCallback((event: KeyboardEvent) => {
if (
(isMac ? event.metaKey : event.ctrlKey) &&
event.shiftKey &&
event.key === 'f'
) {
if (isSplitTestEnabled('full-project-search')) {
setProjectSearchIsOpen(true)
}
}
}, [])
)
// whether to display the editor and preview side-by-side or full-width ("flat")
const [pdfLayout, setPdfLayout] = useScopeValue<IdeLayout>('ui.pdfLayout')
@@ -194,6 +218,8 @@ export const LayoutProvider: FC = ({ children }) => {
leftMenuShown,
pdfLayout,
pdfPreviewOpen,
projectSearchIsOpen,
setProjectSearchIsOpen,
reviewPanelOpen,
miniReviewPanelVisible,
loadingStyleSheet,
@@ -216,6 +242,8 @@ export const LayoutProvider: FC = ({ children }) => {
leftMenuShown,
pdfLayout,
pdfPreviewOpen,
projectSearchIsOpen,
setProjectSearchIsOpen,
reviewPanelOpen,
miniReviewPanelVisible,
loadingStyleSheet,
@@ -1,7 +1,8 @@
import { FC, createContext, useContext, useMemo } from 'react'
import { FC, createContext, useContext, useMemo, useState } from 'react'
import useScopeValue from '../hooks/use-scope-value'
import getMeta from '@/utils/meta'
import { ProjectContextValue } from './types/project-context'
import { ProjectSnapshot } from '@/infrastructure/project-snapshot'
const ProjectContext = createContext<ProjectContextValue | undefined>(undefined)
@@ -43,6 +44,8 @@ export const ProjectProvider: FC = ({ children }) => {
mainBibliographyDoc_id: mainBibliographyDocId,
} = project || projectFallback
const [projectSnapshot] = useState(() => new ProjectSnapshot(_id))
const tags = useMemo(
() =>
(getMeta('ol-projectTags') || [])
@@ -65,6 +68,7 @@ export const ProjectProvider: FC = ({ children }) => {
tags,
trackChangesState,
mainBibliographyDocId,
projectSnapshot,
}
}, [
_id,
@@ -79,6 +83,7 @@ export const ProjectProvider: FC = ({ children }) => {
tags,
trackChangesState,
mainBibliographyDocId,
projectSnapshot,
])
return (
@@ -1,5 +1,6 @@
import { UserId } from '../../../../../types/user'
import { PublicAccessLevel } from '../../../../../types/public-access-level'
import { ProjectSnapshot } from '@/infrastructure/project-snapshot'
export type ProjectContextMember = {
_id: UserId
@@ -46,6 +47,7 @@ export type ProjectContextValue = {
color?: string
}[]
trackChangesState: boolean | Record<UserId | '__guests__', boolean>
projectSnapshot: ProjectSnapshot
}
export type ProjectContextUpdateValue = Partial<ProjectContextValue>
@@ -51,12 +51,12 @@
// Enable ::before and ::after pseudo-elements to position themselves correctly
position: relative;
background-color: @editor-resizer-bg-color;
.custom-toggler {
padding: 0;
border-width: 0;
// Override react-resizable-panels which sets a global * { cursor: ew-resize }
cursor: pointer !important;
}
@@ -74,9 +74,11 @@
width: 7px;
height: 18px;
}
&::before {
top: 25%;
}
&::after {
top: 75%;
}
@@ -89,6 +91,7 @@
.synctex-controls {
left: -8px;
margin: 0;
// Ensure that SyncTex controls appear in front of PDF viewer controls and logs pane
z-index: 12;
@@ -128,6 +131,7 @@
height: 100%;
background-color: @file-tree-bg;
color: var(--neutral-20);
position: relative;
}
.ide-react-symbol-palette {
@@ -60,6 +60,7 @@ $editor-toggler-bg-dark-color: color.adjust(
background-color: var(--file-tree-bg);
height: 100%;
color: var(--content-secondary-dark);
position: relative;
}
.ide-react-body {