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 @@
+
+.SearchPanel
+ ScrollBox
+ .search-groups
+ template(v-for="panel in searchPanels" :key="panel.id")
+ .search-group(v-if="hasMatches(panel)")
+ .group-header(:data-color="panel.reactive.color")
+ img.icon(v-if="!!panel.reactive.iconIMG" :src="panel.reactive.iconIMG")
+ svg.icon(v-else-if="panel.reactive.iconSVG"): use(:href="'#' + panel.reactive.iconSVG")
+ .title {{panel.name}}
+ .group-list
+ TabComponent(v-for="id in getVisibleTabIds(panel)" :key="id" :tabId="id")
+
+
+
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