diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index b82381aa03..6934e4103b 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -310,6 +310,7 @@ "close": "", "close_dialog": "", "close_other_tabs": "", + "close_tab": "", "close_tabs_to_the_right": "", "clsi_maintenance": "", "clsi_unavailable": "", @@ -680,6 +681,10 @@ "features_like_track_changes": "", "feedback": "", "figure": "", + "figure_from_another_project": "", + "figure_from_computer": "", + "figure_from_project_files": "", + "figure_from_url": "", "file": "", "file_action_created": "", "file_action_deleted": "", @@ -976,25 +981,15 @@ "inr_discount_modal_info": "", "inr_discount_modal_title": "", "insert": "", - "insert_citation": "", "insert_column_left": "", "insert_column_right": "", - "insert_cross_reference": "", - "insert_display_math": "", "insert_figure": "", - "insert_figure_from_another_project": "", - "insert_figure_from_computer": "", - "insert_figure_from_project_files": "", - "insert_figure_from_url": "", "insert_from_another_project": "", "insert_from_project_files": "", "insert_from_url": "", "insert_image": "", - "insert_inline_math": "", - "insert_link": "", "insert_row_above": "", "insert_row_below": "", - "insert_table": "", "insert_x_columns_left": "", "insert_x_columns_right": "", "insert_x_rows_above": "", @@ -1055,6 +1050,8 @@ "join_x_managed_enterprise_group": "", "joined_team": "", "joining": "", + "jump_to_line_x": "", + "jump_to_line_x_column_y": "", "jump_to_location_in_pdf": "", "justify": "", "kb_suggestions_enquiry": "", @@ -1444,6 +1441,7 @@ "pdf_compile_in_progress_error": "", "pdf_compile_rate_limit_hit": "", "pdf_compile_try_again": "", + "pdf_in_different_tab": "", "pdf_only": "", "pdf_preview": "", "pdf_preview_error": "", @@ -2145,6 +2143,7 @@ "to_pull_results_directly_from_your_reference_manager_enable_one_of_the_available_reference_manager_integrations": "", "to_use_text_wrapping_in_your_table_make_sure_you_include_the_array_package": "", "toggle_compile_options_menu": "", + "toggle_focus_mode": "", "toggle_group": "", "toggle_personal_library": "", "toggle_unknown_group": "", diff --git a/services/web/frontend/js/features/command-palette/components/command-palette-body.tsx b/services/web/frontend/js/features/command-palette/components/command-palette-body.tsx index 3dc5a70990..2af4aac675 100644 --- a/services/web/frontend/js/features/command-palette/components/command-palette-body.tsx +++ b/services/web/frontend/js/features/command-palette/components/command-palette-body.tsx @@ -111,17 +111,17 @@ const CommandPaletteBody: FC = ({ show, onHide }) => { > ))} diff --git a/services/web/frontend/js/features/command-palette/hooks/use-command-palette-results.ts b/services/web/frontend/js/features/command-palette/hooks/use-command-palette-results.ts index a976f870a7..88fbc9a453 100644 --- a/services/web/frontend/js/features/command-palette/hooks/use-command-palette-results.ts +++ b/services/web/frontend/js/features/command-palette/hooks/use-command-palette-results.ts @@ -1,7 +1,7 @@ import useDebounce from '@/shared/hooks/use-debounce' import useCommandPaletteSources from './use-command-palette-sources' import { useEffect, useState } from 'react' -import { CommandPaletteSearchResult } from '../types' +import { CommandPaletteSearchResult, CommandPaletteSource } from '../types' const useCommandPaletteResults = (query: string) => { const debouncedQuery = useDebounce(query, 25) @@ -9,17 +9,37 @@ const useCommandPaletteResults = (query: string) => { const [results, setResults] = useState([]) useEffect(() => { - if (debouncedQuery) { - const res = sources.map(source => source.search(debouncedQuery)) - setResults(res.flat().sort((a, b) => b.score - a.score)) - } else { - const res = sources - .filter(s => 'defaults' in s) - .map(source => source.defaults!()) - setResults(res.flat().sort((a, b) => b.score - a.score)) - } + const res = getSourcesMatchingQuery(debouncedQuery, sources).map( + ({ source, query }) => + query ? source.search(query) : (source.defaults?.() ?? []) + ) + setResults(res.flat().sort((a, b) => b.score - a.score)) }, [debouncedQuery, sources]) return results } +const getSourcesMatchingQuery = ( + query: string, + sources: CommandPaletteSource[] +): { query: string; source: CommandPaletteSource }[] => { + // No query matches all sources + if (!query) return sources.map(source => ({ source, query })) + + // If the query matches a prefix, return all the sources with that prefix + const matchingSources = sources.filter( + source => source.prefix && query.startsWith(source.prefix) + ) + if (matchingSources.length > 0) { + return matchingSources.map(source => ({ + source, + query: query.slice(source.prefix!.length).trim(), + })) + } + + // otherwise return all sources that don't require a prefix match + return sources + .filter(source => !source.prefixRequired) + .map(source => ({ source, query: query.trim() })) +} + export default useCommandPaletteResults diff --git a/services/web/frontend/js/features/command-palette/hooks/use-command-palette-sources.ts b/services/web/frontend/js/features/command-palette/hooks/use-command-palette-sources.ts index 803009209b..f3f74b836a 100644 --- a/services/web/frontend/js/features/command-palette/hooks/use-command-palette-sources.ts +++ b/services/web/frontend/js/features/command-palette/hooks/use-command-palette-sources.ts @@ -2,13 +2,16 @@ import { useMemo } from 'react' import { CommandPaletteSource } from '../types' import useCommandRegistrySource from './use-command-registry-source' import useFileTreeCommandSource from './use-file-tree-command-source' +import { useJumpToLineCommandSource } from './use-jump-to-line-command-source' const useCommandPaletteSources = (): CommandPaletteSource[] => { const fileTreeSource = useFileTreeCommandSource() const commandRegistrySource = useCommandRegistrySource() + const jumpToLineSource = useJumpToLineCommandSource() + const sources = useMemo( - () => [fileTreeSource, commandRegistrySource], - [fileTreeSource, commandRegistrySource] + () => [fileTreeSource, commandRegistrySource, jumpToLineSource], + [fileTreeSource, commandRegistrySource, jumpToLineSource] ) return sources } diff --git a/services/web/frontend/js/features/command-palette/hooks/use-command-registry-source.tsx b/services/web/frontend/js/features/command-palette/hooks/use-command-registry-source.tsx index 4b32841546..656c4bb2a9 100644 --- a/services/web/frontend/js/features/command-palette/hooks/use-command-registry-source.tsx +++ b/services/web/frontend/js/features/command-palette/hooks/use-command-registry-source.tsx @@ -5,42 +5,85 @@ import { Command, useCommandRegistry, } from '@/features/ide-react/context/command-registry-context' +import { useTranslation } from 'react-i18next' -const ENABLED_COMMANDS: string[] = [ - 'new_file', - 'new_folder', - 'upload_file', - 'open-settings', - 'show_version_history', - 'word_count', - 'view-pdf-presentation-mode', - 'comment', - 'compile', - 'stop-compile', - 'recompile-from-scratch', - 'synctex-sync-to-pdf', - 'synctex-sync-to-code', - 'insert-inline-math', - 'insert-display-math', - 'insert-figure-from-computer', - 'insert-figure-from-project-files', - 'insert-figure-from-another-project', - 'insert-figure-from-url', - 'insert-table', - 'insert-citation', - 'insert-link', - 'insert-cross-reference', -] +type CommandGroup = { + label: string + actions: string[] +} const useCommandRegistrySource = (): CommandPaletteSource => { + const { t } = useTranslation() + const elements: (CommandGroup | string)[] = useMemo( + () => [ + { + label: t('file'), + actions: ['new_file', 'new_folder', 'upload_file'], + }, + { + label: t('view'), + actions: [ + 'change-layout-side-by-side', + 'change-layout-editor-only', + 'change-layout-pdf-only', + 'change-layout-detached-pdf', + 'change-layout-focus-mode', + ], + }, + { + label: t('insert'), + actions: [ + 'insert-inline-math', + 'insert-display-math', + 'insert-figure-from-computer', + 'insert-figure-from-project-files', + 'insert-figure-from-another-project', + 'insert-figure-from-url', + 'insert-table', + 'insert-citation', + 'insert-link', + 'insert-cross-reference', + ], + }, + 'open-settings', + 'show_version_history', + 'word_count', + 'view-pdf-presentation-mode', + 'comment', + 'compile', + 'stop-compile', + 'recompile-from-scratch', + 'synctex-sync-to-pdf', + 'synctex-sync-to-code', + 'close-tab', + 'close-other-tabs', + ], + [t] + ) const { registry } = useCommandRegistry() const commands = useMemo(() => { - const enabled = new Set(ENABLED_COMMANDS) - return [...registry.values()].filter( - c => enabled.has(c.id) && !c.disabled && c.handler - ) - }, [registry]) + const ret: Command[] = [] + for (const element of elements) { + if (typeof element === 'string') { + const command = registry.get(element) + if (command && !command.disabled && command.handler) { + ret.push(command) + } + } else { + for (const action of element.actions) { + const command = registry.get(action) + if (command && !command.disabled && command.handler) { + ret.push({ + ...command, + label: `${element.label}: ${command.label}`, + }) + } + } + } + } + return ret + }, [registry, elements]) const defaults = useCallback((): CommandPaletteSearchResult[] => { return commands.map(command => ({ @@ -53,7 +96,7 @@ const useCommandRegistrySource = (): CommandPaletteSource => { const index = useMemo(() => { const miniSearch = new MiniSearch({ fields: ['label'], - storeFields: ['id'], + storeFields: ['id', 'label'], idField: 'id', }) miniSearch.addAll(commands) @@ -63,17 +106,18 @@ const useCommandRegistrySource = (): CommandPaletteSource => { return useMemo( () => ({ id: 'command-registry', + prefix: '>', search(query) { const results = index.search(query, { prefix: true, fuzzy: term => (term.length > 3 ? 0.2 : false), }) - return results.flatMap(({ id, score }) => { + return results.flatMap(({ id, label, score }) => { const command = registry.get(id) if (!command?.handler) return [] return [ { - title: command.label, + title: label, onSelect: () => command.handler!({ location: 'command-palette' }), score, }, diff --git a/services/web/frontend/js/features/command-palette/hooks/use-file-tree-command-source.ts b/services/web/frontend/js/features/command-palette/hooks/use-file-tree-command-source.ts index ebb6125c6d..0d7f53c82e 100644 --- a/services/web/frontend/js/features/command-palette/hooks/use-file-tree-command-source.ts +++ b/services/web/frontend/js/features/command-palette/hooks/use-file-tree-command-source.ts @@ -9,9 +9,12 @@ import { useEditorManagerContext } from '@/features/ide-react/context/editor-man type FlatFileTree = { path: string; name: string; id: string }[] +const FILE_POSITION_REGEX = /:(\d+)(?:,(\d+))?$/ + const useFileTreeCommandSource = (): CommandPaletteSource => { const { fileTreeData } = useFileTreeData() const { openDocWithId, openFileWithId } = useEditorManagerContext() + const flatFileTree = useMemo( () => flattenFileTree(fileTreeData), [fileTreeData] @@ -22,7 +25,11 @@ const useFileTreeCommandSource = (): CommandPaletteSource => { ) const onSelect = useCallback( - async (id: string) => { + async ( + id: string, + line: number | undefined, + column: number | undefined + ) => { if (!fileTreeData) { return } @@ -31,7 +38,10 @@ const useFileTreeCommandSource = (): CommandPaletteSource => { return } if (file.type === 'doc') { - await openDocWithId(file.entity._id) + await openDocWithId(file.entity._id, { + gotoLine: line, + gotoColumn: column, + }) } else if (file.type === 'fileRef') { openFileWithId(file.entity._id) } else { @@ -49,8 +59,9 @@ const useFileTreeCommandSource = (): CommandPaletteSource => { .slice(0, 10) .map(({ path, name, id }) => ({ title: name, - description: path === name ? undefined : path, - onSelect: () => onSelect(id), + description: + path === name ? undefined : path.split('/').slice(0, -1).join('/'), + onSelect: () => onSelect(id, undefined, undefined), score: 1, })) @@ -64,14 +75,27 @@ const useFileTreeCommandSource = (): CommandPaletteSource => { if (!index) { return [] } + const fileLocationMatch = query.match(FILE_POSITION_REGEX) + let line: number | undefined = undefined + let column: number | undefined = undefined + if (fileLocationMatch) { + line = parseInt(fileLocationMatch[1], 10) + column = fileLocationMatch[2] + ? parseInt(fileLocationMatch[2], 10) + : undefined + query = query.slice(0, fileLocationMatch.index) + } + const result = index.search(query, { prefix: true, fuzzy: term => (term.length > 3 ? 0.2 : false), }) + return result.map(({ path, name, id, score }) => ({ title: name, - description: path === name ? undefined : path, - onSelect: () => onSelect(id), + description: + path === name ? undefined : path.split('/').slice(0, -1).join('/'), + onSelect: () => onSelect(id, line, column), score, })) }, diff --git a/services/web/frontend/js/features/command-palette/hooks/use-jump-to-line-command-source.ts b/services/web/frontend/js/features/command-palette/hooks/use-jump-to-line-command-source.ts new file mode 100644 index 0000000000..e91aa5250f --- /dev/null +++ b/services/web/frontend/js/features/command-palette/hooks/use-jump-to-line-command-source.ts @@ -0,0 +1,43 @@ +import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context' +import { CommandPaletteSource } from '../types' +import { useMemo } from 'react' +import { useTranslation } from 'react-i18next' + +const JUMP_REGEX = /^(\d+)(?:,(\d+))?$/ + +export const useJumpToLineCommandSource = (): CommandPaletteSource => { + const { jumpToLine } = useEditorManagerContext() + const { t } = useTranslation() + return useMemo( + () => ({ + id: 'jump-to-line-source', + prefix: ':', + prefixRequired: true, + search: (query: string) => { + const match = query.match(JUMP_REGEX) + if (!match) { + return [] + } + const line = parseInt(match[1], 10) + const column = match[2] ? parseInt(match[2], 10) : undefined + + return [ + { + onSelect: () => jumpToLine({ gotoLine: line, gotoColumn: column }), + title: + column != null + ? t('jump_to_line_x_column_y', { + line, + column, + }) + : t('jump_to_line_x', { + line, + }), + score: 1, + }, + ] + }, + }), + [jumpToLine, t] + ) +} diff --git a/services/web/frontend/js/features/command-palette/types.ts b/services/web/frontend/js/features/command-palette/types.ts index 4aeefc4cf8..df117261f3 100644 --- a/services/web/frontend/js/features/command-palette/types.ts +++ b/services/web/frontend/js/features/command-palette/types.ts @@ -9,4 +9,6 @@ export type CommandPaletteSource = { id: string search(query: string): CommandPaletteSearchResult[] defaults?(): CommandPaletteSearchResult[] + prefix?: string + prefixRequired?: boolean } diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-create-name-input.tsx b/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-create-name-input.tsx index 9d9109bf92..df62a65a46 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-create-name-input.tsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-create-name-input.tsx @@ -1,4 +1,4 @@ -import { useRef, useEffect } from 'react' +import { useRef, useEffect, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { useFileTreeCreateName } from '../../contexts/file-tree-create-name' import { @@ -36,6 +36,7 @@ export default function FileTreeCreateNameInput({ // the value is stored in a context provider, so it's available elsewhere in the form const { name, setName, touchedName, validName } = useFileTreeCreateName() + const nameFocusedOnce = useRef(false) // focus the first part of the filename if needed const inputRef = useRef(null) @@ -45,15 +46,24 @@ export default function FileTreeCreateNameInput({ window.requestAnimationFrame(() => { if (inputRef.current) { inputRef.current.focus() - inputRef.current.setSelectionRange( - 0, - inputRef.current.value.lastIndexOf('.') - ) } }) } }, [focusName]) + const onFocus = useCallback(() => { + if (nameFocusedOnce.current) return + if (!focusName) return + window.requestAnimationFrame(() => { + if (!inputRef.current) return + nameFocusedOnce.current = true + inputRef.current.setSelectionRange( + 0, + inputRef.current.value.lastIndexOf('.') + ) + }) + }, [focusName]) + return ( {label || t('file_name')} @@ -65,6 +75,7 @@ export default function FileTreeCreateNameInput({ onChange={event => setName(event.target.value)} ref={inputRef} disabled={inFlight} + onFocus={onFocus} /> {touchedName && !validName && (
diff --git a/services/web/frontend/js/features/ide-react/components/toolbar/change-layout-button.tsx b/services/web/frontend/js/features/ide-react/components/toolbar/change-layout-button.tsx index debe5ed0da..2c3c32918d 100644 --- a/services/web/frontend/js/features/ide-react/components/toolbar/change-layout-button.tsx +++ b/services/web/frontend/js/features/ide-react/components/toolbar/change-layout-button.tsx @@ -8,6 +8,10 @@ import { import ChangeLayoutOptions from './change-layout-options' import MaterialIcon from '@/shared/components/material-icon' import OLTooltip from '@/shared/components/ol/ol-tooltip' +import { useCommandProvider } from '../../hooks/use-command-provider' +import { useFeatureFlag } from '@/shared/context/split-test-context' +import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics' +import { useLayoutContext } from '@/shared/context/layout-context' export default function ChangeLayoutButton() { const { t } = useTranslation() @@ -17,6 +21,71 @@ export default function ChangeLayoutButton() { 'ide-redesign-toolbar-button-icon' ) + const { + detachIsLinked, + detachRole, + handleChangeLayout, + handleDetach, + focusMode, + setFocusMode, + } = useLayoutContext() + + const { sendEvent } = useEditorAnalytics() + const focusModeEnabled = useFeatureFlag('focus-mode') + + const detachable = 'BroadcastChannel' in window + + const waitingForDetachedLink = !detachIsLinked && detachRole === 'detacher' + + useCommandProvider( + () => [ + { + id: 'change-layout-side-by-side', + handler: () => handleChangeLayout('sideBySide'), + label: t('split_view'), + }, + { + id: 'change-layout-editor-only', + handler: () => handleChangeLayout('flat', 'editor'), + label: t('editor_only'), + }, + { + id: 'change-layout-pdf-only', + handler: () => handleChangeLayout('flat', 'pdf'), + label: t('pdf_only'), + }, + { + id: 'change-layout-detached-pdf', + handler: () => handleDetach(), + disabled: !detachable || waitingForDetachedLink, + label: t('pdf_in_different_tab'), + }, + ...(focusModeEnabled + ? [ + { + id: 'change-layout-focus-mode', + handler: () => { + setFocusMode(!focusMode) + sendEvent('focus-mode-toggle', { focusMode: !focusMode }) + }, + label: t('toggle_focus_mode'), + }, + ] + : []), + ], + [ + handleChangeLayout, + t, + detachable, + handleDetach, + waitingForDetachedLink, + focusModeEnabled, + focusMode, + setFocusMode, + sendEvent, + ] + ) + return (
diff --git a/services/web/frontend/js/features/source-editor/components/tabs/tabs-container.tsx b/services/web/frontend/js/features/source-editor/components/tabs/tabs-container.tsx index 61954f7006..68ebac4e2f 100644 --- a/services/web/frontend/js/features/source-editor/components/tabs/tabs-container.tsx +++ b/services/web/frontend/js/features/source-editor/components/tabs/tabs-container.tsx @@ -10,6 +10,8 @@ import { useCallback, useMemo, useState } from 'react' import { throttle } from 'lodash' import { debugConsole } from '@/utils/debugging' import classNames from 'classnames' +import { useCommandProvider } from '@/features/ide-react/hooks/use-command-provider' +import { useTranslation } from 'react-i18next' export const TabsContainer = () => { const { @@ -20,9 +22,11 @@ export const TabsContainer = () => { makeTabPermanent, setContextMenuTarget, setHeaderSlot, + closeOtherTabs, } = useTabsContext() const { openEntity } = useFileTreeOpenContext() const [hovered, setHovered] = useState(false) + const { t } = useTranslation() const openContextMenu = useCallback( (coords: { top: number; left: number }, tabId: string) => { @@ -86,6 +90,32 @@ export const TabsContainer = () => { } }, []) + useCommandProvider(() => { + if (tabs.length === 0) { + return + } + if (!openEntity?.entity._id) { + return + } + + return [ + { + id: 'close-tab', + label: t('close_tab'), + handler: () => { + closeTab(openEntity.entity._id) + }, + }, + { + id: 'close-other-tabs', + label: t('close_other_tabs'), + handler: () => { + closeOtherTabs(openEntity.entity._id) + }, + }, + ] + }, [tabs, t, openEntity, closeTab, closeOtherTabs]) + return (
diff --git a/services/web/frontend/js/features/source-editor/hooks/use-toolbar-menu-editor-commands.tsx b/services/web/frontend/js/features/source-editor/hooks/use-toolbar-menu-editor-commands.tsx index 549cd9a9a1..397e7a6473 100644 --- a/services/web/frontend/js/features/source-editor/hooks/use-toolbar-menu-editor-commands.tsx +++ b/services/web/frontend/js/features/source-editor/hooks/use-toolbar-menu-editor-commands.tsx @@ -102,7 +102,7 @@ export const useToolbarMenuBarEditorCommands = () => { { id: 'insert-inline-math', menuLabel: t('inline_math'), - label: t('insert_inline_math'), + label: t('inline_math'), handler: () => { commands.wrapInInlineMath(view) view.focus() @@ -111,7 +111,7 @@ export const useToolbarMenuBarEditorCommands = () => { { id: 'insert-display-math', menuLabel: t('display_math'), - label: t('insert_display_math'), + label: t('display_math'), handler: () => { commands.wrapInDisplayMath(view) view.focus() @@ -119,7 +119,7 @@ export const useToolbarMenuBarEditorCommands = () => { }, { menuLabel: t('upload_from_computer'), - label: t('insert_figure_from_computer'), + label: t('figure_from_computer'), id: 'insert-figure-from-computer', handler: () => { openFigureModal(FigureModalSource.FILE_UPLOAD) @@ -127,7 +127,7 @@ export const useToolbarMenuBarEditorCommands = () => { }, { menuLabel: t('from_project_files'), - label: t('insert_figure_from_project_files'), + label: t('figure_from_project_files'), id: 'insert-figure-from-project-files', handler: () => { openFigureModal(FigureModalSource.FILE_TREE) @@ -149,7 +149,7 @@ export const useToolbarMenuBarEditorCommands = () => { return [ { menuLabel: t('from_another_project'), - label: t('insert_figure_from_another_project'), + label: t('figure_from_another_project'), id: 'insert-figure-from-another-project', handler: () => { openFigureModal(FigureModalSource.OTHER_PROJECT) @@ -179,7 +179,7 @@ export const useToolbarMenuBarEditorCommands = () => { return [ { menuLabel: t('from_url'), - label: t('insert_figure_from_url'), + label: t('figure_from_url'), id: 'insert-figure-from-url', handler: () => { openFigureModal(FigureModalSource.FROM_URL) @@ -206,8 +206,7 @@ export const useToolbarMenuBarEditorCommands = () => { return [ { id: 'insert-table', - menuLabel: t('table'), - label: t('insert_table'), + label: t('table'), handler: () => { commands.insertTable(view, 3, 3) view.focus() @@ -215,8 +214,7 @@ export const useToolbarMenuBarEditorCommands = () => { }, { id: 'insert-citation', - menuLabel: t('citation'), - label: t('insert_citation'), + label: t('citation'), handler: () => { commands.insertCite(view) view.focus() @@ -224,8 +222,7 @@ export const useToolbarMenuBarEditorCommands = () => { }, { id: 'insert-link', - menuLabel: t('link'), - label: t('insert_link'), + label: t('link'), handler: () => { commands.wrapInHref(view) view.focus() @@ -233,8 +230,7 @@ export const useToolbarMenuBarEditorCommands = () => { }, { id: 'insert-cross-reference', - menuLabel: t('cross_reference'), - label: t('insert_cross_reference'), + label: t('cross_reference'), handler: () => { commands.insertRef(view) view.focus() diff --git a/services/web/frontend/stylesheets/pages/editor/command-palette.scss b/services/web/frontend/stylesheets/pages/editor/command-palette.scss index da5116b1b2..6efff438c1 100644 --- a/services/web/frontend/stylesheets/pages/editor/command-palette.scss +++ b/services/web/frontend/stylesheets/pages/editor/command-palette.scss @@ -83,22 +83,19 @@ background-color: var(--command-palette-selected-bg); color: var(--command-palette-selected-color); } - - &.command-palette-result-selected .command-palette-result-description { - color: var(--command-palette-selected-color); - } } .command-palette-result-title { color: var(--content-primary-themed); - font-size: var(--font-size-03); + font-size: var(--font-size-02); font-weight: 500; line-height: 1.2; } .command-palette-result-description { font-size: var(--font-size-02); - color: var(--content-secondary-themed); + margin-left: var(--spacing-02); + color: var(--content-placeholder-themed); line-height: 1.2; } } diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 32de070bf9..28f8616505 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -402,6 +402,7 @@ "close": "Close", "close_dialog": "Close dialog", "close_other_tabs": "Close other tabs", + "close_tab": "Close tab", "close_tabs_to_the_right": "Close tabs to the right", "clsi_maintenance": "The compile servers are down for maintenance, and will be back shortly.", "clsi_unavailable": "Sorry, the compile server for your project was temporarily unavailable. Please try again in a few moments.", @@ -888,6 +889,10 @@ "fedramp_li_saas": "FedRAMP® Li-SaaS authorized solution", "feedback": "Feedback", "figure": "Figure", + "figure_from_another_project": "Figure from another project", + "figure_from_computer": "Figure from your computer", + "figure_from_project_files": "Figure from project files", + "figure_from_url": "Figure from URL", "file": "File", "file_action_created": "Created", "file_action_deleted": "Deleted", @@ -1244,25 +1249,15 @@ "inr_discount_modal_title": "70% off all Overleaf premium plans for users in India", "inr_discount_offer_plans_page_banner": "__flag__ Great news! We’ve applied a 70% discount to premium plans for our users in India. Check out the new lower prices below.", "insert": "Insert", - "insert_citation": "Insert citation", "insert_column_left": "Insert column left", "insert_column_right": "Insert column right", - "insert_cross_reference": "Insert cross reference", - "insert_display_math": "Insert display math", "insert_figure": "Insert figure", - "insert_figure_from_another_project": "Insert figure from another project", - "insert_figure_from_computer": "Insert figure from your computer", - "insert_figure_from_project_files": "Insert figure from project files", - "insert_figure_from_url": "Insert figure from URL", "insert_from_another_project": "Insert from another project", "insert_from_project_files": "Insert from project files", "insert_from_url": "Insert from URL", "insert_image": "Insert image", - "insert_inline_math": "Insert inline math", - "insert_link": "Insert link", "insert_row_above": "Insert row above", "insert_row_below": "Insert row below", - "insert_table": "Insert table", "insert_x_columns_left": "Insert __columns__ columns left", "insert_x_columns_right": "Insert __columns__ columns right", "insert_x_rows_above": "Insert __rows__ rows above", @@ -1357,6 +1352,8 @@ "joined_team": "You have joined the group subscription managed by __inviterName__", "joining": "Joining", "july": "July", + "jump_to_line_x": "Jump to line __line__", + "jump_to_line_x_column_y": "Jump to line __line__, column __column__", "jump_to_location_in_pdf": "Jump to location in PDF", "june": "June", "justify": "Justify", @@ -1894,6 +1891,7 @@ "pdf_compile_in_progress_error": "A previous compile is still running. Please wait a minute and try compiling again.", "pdf_compile_rate_limit_hit": "Compile rate limit hit", "pdf_compile_try_again": "Please wait for your other compile to finish before trying again.", + "pdf_in_different_tab": "PDF in different tab", "pdf_only": "PDF only", "pdf_preview": "PDF preview", "pdf_preview_error": "There was a problem displaying the compilation results for this project.", @@ -2758,6 +2756,7 @@ "to_pull_results_directly_from_your_reference_manager_enable_one_of_the_available_reference_manager_integrations": "To pull results directly from your reference manager, <0>enable one of the available reference manager integrations.", "to_use_text_wrapping_in_your_table_make_sure_you_include_the_array_package": "<0>Please note: To use text wrapping in your table, make sure you include the <1>array package in your document preamble:", "toggle_compile_options_menu": "Toggle compile options menu", + "toggle_focus_mode": "Toggle focus mode", "toggle_unknown_group": "Toggle unknown group", "token": "Token", "token_access_failure": "Cannot grant access; contact the project owner for help",