diff --git a/src/_locales/dict.setup-page.ts b/src/_locales/dict.setup-page.ts index 5341b82ce..334b05e19 100644 --- a/src/_locales/dict.setup-page.ts +++ b/src/_locales/dict.setup-page.ts @@ -2538,6 +2538,9 @@ Vous pouvez également définir des préfixes pour chaque type de commande pour en: 'Keep searching after triggering the context menu option', fr: 'Continuer à chercher après avoir déclenché l’option du menu contextuel', }, + 'settings.search_all_panels_default': { + en: 'Search all panels by default (invert "/" prefix behavior)', + }, 'settings.search.shortcuts': { en: 'Shortcuts', de: 'Tastenkombinationen', diff --git a/src/defaults/settings.ts b/src/defaults/settings.ts index 8e63bacb8..9a3bc2802 100644 --- a/src/defaults/settings.ts +++ b/src/defaults/settings.ts @@ -78,6 +78,7 @@ export const DEFAULT_SETTINGS: SettingsState = { searchPanelSwitch: 'same_type', searchTabSwitch: false, searchMenuTrig: false, + searchAllPanelsDefault: false, searchBookmarksShortcut: '', searchHistoryShortcut: '', searchInputTimeout: 300, diff --git a/src/page.setup/components/settings.search.vue b/src/page.setup/components/settings.search.vue index 1c759f0fc..898219dfc 100644 --- a/src/page.setup/components/settings.search.vue +++ b/src/page.setup/components/settings.search.vue @@ -31,6 +31,12 @@ section(ref="el") dbg="searchMenuTrig" :default="DEFAULT_SETTINGS.searchMenuTrig" @update:value="Settings.saveDebounced(150)") + ToggleField( + label="settings.search_all_panels_default" + v-model:value="Settings.state.searchAllPanelsDefault" + dbg="searchAllPanelsDefault" + :default="DEFAULT_SETTINGS.searchAllPanelsDefault" + @update:value="Settings.saveDebounced(150)") InfoField( label="settings.search.shortcuts" :value="translate('settings.search.shortcuts.note')") diff --git a/src/services/search.fg.tabs.ts b/src/services/search.fg.tabs.ts index 4c2fce445..59c96676e 100644 --- a/src/services/search.fg.tabs.ts +++ b/src/services/search.fg.tabs.ts @@ -60,18 +60,35 @@ export function onTabsSearch(activePanel: Panel): void { } } -export function onTabsSearchNext(panel?: Panel): void { - if (!panel) panel = Sidebar.panelsById[Sidebar.activePanelId] - if (!Utils.isTabsPanel(panel) || !panel.filteredTabs) return +function getFilteredTabs(panel?: Panel): Tab[] { + let filteredTabs: Tab[] = [] + if (Search.reactive.allPanels) { + for (const p of Sidebar.panels) { + if (Utils.isTabsPanel(p) && p.filteredTabs) { + filteredTabs.push(...p.filteredTabs) + } + } + } else { + if (!panel) panel = Sidebar.panelsById[Sidebar.activePanelId] + if (Utils.isTabsPanel(panel) && panel.filteredTabs) { + filteredTabs = panel.filteredTabs + } + } + return filteredTabs +} +export function onTabsSearchNext(panel?: Panel): void { + const filteredTabs = getFilteredTabs(panel) + if (!filteredTabs.length) return + const selId = Selection.getFirst() - let index = panel.filteredTabs.findIndex(t => t.id === selId) + let index = filteredTabs.findIndex(t => t.id === selId) index += 1 - if (index < 0 || index >= panel.filteredTabs.length) return + if (index < 0 || index >= filteredTabs.length) return Selection.resetSelection() - const tab = panel.filteredTabs[index] + const tab = filteredTabs[index] if (tab) { Selection.selectTab(tab.id) Tabs.scrollToTab(tab.id, true) @@ -79,21 +96,22 @@ export function onTabsSearchNext(panel?: Panel): void { } export function onTabsSearchPrev(panel?: Panel): void { - if (!panel) panel = Sidebar.panelsById[Sidebar.activePanelId] - if (!Utils.isTabsPanel(panel) || !panel.filteredTabs) return + const filteredTabs = getFilteredTabs(panel) + + if (!filteredTabs.length) return const selId = Selection.getFirst() - let index = panel.filteredTabs.findIndex(t => t.id === selId) + let index = filteredTabs.findIndex(t => t.id === selId) - if (index === -1 && panel.filteredTabs.length) { - index = panel.filteredTabs.length + if (index === -1 && filteredTabs.length) { + index = filteredTabs.length } index -= 1 - if (index < 0 || index >= panel.filteredTabs.length) return + if (index < 0 || index >= filteredTabs.length) return Selection.resetSelection() - const tab = panel.filteredTabs[index] + const tab = filteredTabs[index] if (tab) { Selection.selectTab(tab.id) Tabs.scrollToTab(tab.id, true) @@ -101,10 +119,13 @@ export function onTabsSearchPrev(panel?: Panel): void { } export function onTabsSearchEnter(panel?: Panel): void { - if (!Utils.isTabsPanel(panel)) return + // If in all panels mode, we don't strictly require the passed panel to be valid. + if (!Search.reactive.allPanels && !Utils.isTabsPanel(panel)) return // Try to find in another panel - if (Search.query && !panel.filteredTabs?.length) return findInAnotherPanel() + if (Search.query && !Search.reactive.allPanels && (!panel || !Utils.isTabsPanel(panel) || !panel.filteredTabs?.length)) { + return findInAnotherPanel() + } const selId = Selection.getFirst() const tab = Tabs.byId[selId] diff --git a/src/services/search.fg.ts b/src/services/search.fg.ts index 60285a720..fb08343e6 100644 --- a/src/services/search.fg.ts +++ b/src/services/search.fg.ts @@ -24,6 +24,7 @@ export interface SearchState { barIsFilled: boolean active: boolean rawQuery: string + allPanels: boolean } export interface SearchShortcut { @@ -45,6 +46,7 @@ export let reactive: SearchState = { barIsFilled: false, active: false, rawQuery: '', + allPanels: false, } export let active = false @@ -114,6 +116,10 @@ export function next(): void { if (!Search.reactive.barIsShowed) return if (Menu.isOpen) return Menu.selectOption(1) + if (reactive.allPanels) { + return SearchTabs.onTabsSearchNext(undefined) + } + const actPanel = Sidebar.panelsById[Sidebar.activePanelId] if (!actPanel) return @@ -135,6 +141,10 @@ export function prev(): void { if (!Search.reactive.barIsShowed) return if (Menu.isOpen) return Menu.selectOption(-1) + if (reactive.allPanels) { + return SearchTabs.onTabsSearchPrev(undefined) + } + const actPanel = Sidebar.panelsById[Sidebar.activePanelId] if (!actPanel) return @@ -154,11 +164,10 @@ export function prev(): void { export function enter(): void { if (!Search.reactive.barIsShowed) return + if (Menu.isOpen) return Menu.activateOption() - if (Menu.isOpen) { - const activated = Menu.activateOption() - if (activated) Search.close() - return + if (reactive.allPanels) { + return SearchTabs.onTabsSearchEnter(undefined) } const actPanel = Sidebar.panelsById[Sidebar.activePanelId] @@ -276,6 +285,8 @@ export function selectAll(): void { if (!Search.reactive.barIsShowed) return if (Menu.isOpen) return + if (reactive.allPanels) return + const actPanel = Sidebar.panelsById[Sidebar.activePanelId] if (!actPanel) return @@ -356,13 +367,20 @@ export function search(q?: string): void { // Update query if (q !== undefined) { + let isGlobal = Settings.state.searchAllPanelsDefault + if (q.startsWith('/')) { + isGlobal = !isGlobal + q = q.slice(1).trimStart() + } + if (q.length < MIN_SEARCH_QUERY_LEN && !regexCJK.test(q)) q = '' - if (query === q) return + if (query === q && reactive.allPanels === isGlobal) return query = q lowerCaseQuery = q.toLowerCase() const v = !!q if (active !== v) reactive.active = active = v + reactive.allPanels = isGlobal && v } if (Menu.isOpen) Menu.close() @@ -385,23 +403,29 @@ export function search(q?: string): void { if (!actPanel) return let targetPanelId = actPanel.id - if (Utils.isTabsPanel(actPanel)) { - if (Sidebar.subPanelActive) { - if (Sidebar.subPanelType === SubPanelType.Bookmarks && Sidebar.subPanels.bookmarks) { - targetPanelId = Sidebar.subPanels.bookmarks.id - SearchBookmarks.onBookmarksSearch(actPanel, Sidebar.subPanels.bookmarks) - } else if (Sidebar.subPanelType === SubPanelType.History) { - targetPanelId = NOID - SearchHistory.onHistorySearch() + if (reactive.allPanels && query) { + for (const panel of Sidebar.panels) { + if (Utils.isTabsPanel(panel)) SearchTabs.onTabsSearch(panel) + } + } else { + if (Utils.isTabsPanel(actPanel)) { + if (Sidebar.subPanelActive) { + if (Sidebar.subPanelType === SubPanelType.Bookmarks && Sidebar.subPanels.bookmarks) { + targetPanelId = Sidebar.subPanels.bookmarks.id + SearchBookmarks.onBookmarksSearch(actPanel, Sidebar.subPanels.bookmarks) + } else if (Sidebar.subPanelType === SubPanelType.History) { + targetPanelId = NOID + SearchHistory.onHistorySearch() + } + } else { + SearchTabs.onTabsSearch(actPanel) } - } else { - SearchTabs.onTabsSearch(actPanel) + } else if (Utils.isBookmarksPanel(actPanel)) { + SearchBookmarks.onBookmarksSearch(actPanel, undefined) + } else if (Utils.isHistoryPanel(actPanel)) { + targetPanelId = NOID + SearchHistory.onHistorySearch() } - } else if (Utils.isBookmarksPanel(actPanel)) { - SearchBookmarks.onBookmarksSearch(actPanel, undefined) - } else if (Utils.isHistoryPanel(actPanel)) { - targetPanelId = NOID - SearchHistory.onHistorySearch() } if (query === '') { diff --git a/src/sidebar/components/panel.search.vue b/src/sidebar/components/panel.search.vue new file mode 100644 index 000000000..6e8794be6 --- /dev/null +++ b/src/sidebar/components/panel.search.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/sidebar/sidebar.vue b/src/sidebar/sidebar.vue index 370ec6483..4824dcc20 100644 --- a/src/sidebar/sidebar.vue +++ b/src/sidebar/sidebar.vue @@ -86,6 +86,7 @@ :is="getPanelComponent(panel)" :data-pos="panel.reactive.pos" :panel="panel") + SearchPanel(v-if="Search.reactive.active && Search.reactive.allPanels") Transition(name="bottom-bar") .BottomBar( @@ -156,6 +157,7 @@ import PinnedTabsBar from './components/bar.pinned-tabs.vue' import NotificationsPopup from './components/popup.notifications.vue' import NavigationBar from './components/bar.navigation.vue' import WindowsPopup from './components/popup.windows.vue' +import SearchPanel from './components/panel.search.vue' import TabsPanel from './components/panel.tabs.vue' import BookmarksPanel from './components/panel.bookmarks.vue' import HistoryPanel from './components/panel.history.vue' diff --git a/src/styles/sidebar/bar.navigation.styl b/src/styles/sidebar/bar.navigation.styl index ce7c0de77..71b623325 100644 --- a/src/styles/sidebar/bar.navigation.styl +++ b/src/styles/sidebar/bar.navigation.styl @@ -227,7 +227,7 @@ opacity: 0 z-index: -1 transform: scale(0, 0) - + // Button x position for i in 0..24 &[data-index=\"{i}\"] diff --git a/src/styles/sidebar/panel.search.styl b/src/styles/sidebar/panel.search.styl new file mode 100644 index 000000000..19570bdc9 --- /dev/null +++ b/src/styles/sidebar/panel.search.styl @@ -0,0 +1,36 @@ +.SearchPanel + position: absolute + top: 0 + left: 0 + width: 100% + height: 100% + background-color: var(--frame-bg) + z-index: 20 + display: flex + flex-direction: column + +.SearchPanel .search-groups + padding: var(--general-margin) + display: flex + flex-direction: column + grid-gap: var(--general-margin) + +.SearchPanel .search-group + display: flex + flex-direction: column + +.SearchPanel .group-header + display: flex + align-items: center + font-size: rem(14) + font-weight: 600 + color: var(--title-fg) + padding: 4px 8px + border-bottom: 1px solid var(--border-color) + margin-bottom: 4px + +.SearchPanel .group-header .icon + width: 16px + height: 16px + margin-right: 8px + fill: var(--color, var(--title-fg)) diff --git a/src/styles/sidebar/sidebar.styl b/src/styles/sidebar/sidebar.styl index b49cbe606..37773d306 100644 --- a/src/styles/sidebar/sidebar.styl +++ b/src/styles/sidebar/sidebar.styl @@ -28,6 +28,7 @@ vendors = official @import './panel.tabs' @import './panel.bookmarks' @import './panel.history' +@import './panel.search' @import './popup.windows' @import './popup.confirm' @import './popup.processing-tabs' diff --git a/src/types/settings.ts b/src/types/settings.ts index 7644b30b6..67d612490 100644 --- a/src/types/settings.ts +++ b/src/types/settings.ts @@ -77,6 +77,7 @@ export interface SettingsState { searchPanelSwitch: (typeof SETTINGS_OPTIONS.searchPanelSwitch)[number] searchTabSwitch: boolean searchMenuTrig: boolean + searchAllPanelsDefault: boolean searchBookmarksShortcut: string searchHistoryShortcut: string searchInputTimeout: number