Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ build/*
!build/*.mjs
/.devenv/
/.direnv/
.idea
.idea
.thinktank
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sidebery",
"version": "5.6.1",
"version": "5.6.2",
"description": "Manage your tabs and bookmarks in sidebar",
"main": "index.js",
"type": "module",
Expand Down
54 changes: 54 additions & 0 deletions src/_locales/dict.setup-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1825,6 +1825,13 @@ Vous pouvez également définir des préfixes pour chaque type de commande pour
zh: '同步子面板',
ja: '同期サブパネル',
},
'settings.sub_panel.tab_search': {
en: 'Tab search bar',
ru: 'Поиск вкладок',
zh_CN: '标签页搜索栏',
zh_TW: '分頁搜尋列',
ja: 'タブ検索バー',
},
'settings.nav_bar_enabled': {
en: 'Enabled elements',
de: 'Aktivierte Elemente',
Expand Down Expand Up @@ -3999,6 +4006,53 @@ Available parameters:
ja: '他のタブの前にグループを並べ替える',
},

// - Domain trees
'settings.nav_settings_domain_trees': {
en: 'Domain Trees (Inline Panels)',
},
'settings.domain_trees': {
en: 'Auto-group tabs by domain into inline trees',
},
'settings.domain_trees_universal': {
en: 'Auto-group any domain with 2 or more tabs',
},
'settings.domain_tree_auto_fold': {
en: 'Auto-fold domain trees',
},
'settings.domain_tree_confirm_close': {
en: 'Confirm before closing domain tree placeholder',
},
'settings.domain_tree_rules': {
en: 'Domain tree rules',
},
'settings.domain_tree_new_tab_position': {
en: 'Position of new tabs in domain tree',
},
'settings.domain_tree_new_tab_position_first_child': {
en: 'Top of tree (first child)',
},
'settings.domain_tree_new_tab_position_last_child': {
en: 'Bottom of tree (last child)',
},
'settings.domain_tree_rules_note': {
en: 'Specify domain rules (e.g. "Media: youtube|youtu.be|spotify|bandcamp" or "youtube.com|youtu.be"). One rule per line.',
},
'settings.domain_trees_recalc': {
en: 'Group open tabs now',
},
'settings.domain_trees_view_logs': {
en: 'View domain trees logs',
},
'settings.domain_trees_copy_logs': {
en: 'Copy domain trees logs',
},
'settings.domain_trees_clear_logs': {
en: 'Clear logs',
},
'settings.domain_trees_logs_copied': {
en: 'Domain trees logs copied to clipboard',
},

// - Tabs colorization
'settings.colorize_tabs': {
en: 'Colorize tabs',
Expand Down
10 changes: 10 additions & 0 deletions src/_locales/dict.sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ export const sidebarTranslations: Translations = {
zh_TW: '搜尋...',
ja: '検索...',
},
'bar.search.tabs_placeholder': {
en: 'Search tabs... (F8)',
ru: 'Поиск вкладок... (F8)',
zh_CN: '搜索标签页... (F8)',
zh_TW: '搜尋分頁... (F8)',
ja: 'タブを検索... (F8)',
},

// ---
// -- Confirm dialogs
Expand Down Expand Up @@ -49,6 +56,9 @@ export const sidebarTranslations: Translations = {
zh_TW: n => `您確定要關閉 ${n} 個分頁嗎?`,
ja: n => `本当に${n}個のタブを閉じますか?`,
},
'confirm.domain_tree_close': {
en: (domain, n) => `Close "${domain}" domain tree and its ${n} tabs?`,
},
'confirm.bookmarks_delete': {
en: 'Are you sure you want to delete selected bookmarks?',
de: 'Möchten Sie die gewählten Lesezeichen wirklich löschen?',
Expand Down
2 changes: 2 additions & 0 deletions src/components/text-field.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
:password="props.password"
:valid="props.valid"
:width="props.inputWidth"
:resize="props.resize"
@update:value="emit('update:value', $event)"
@blur="onBlur"
@keydown="emit('keydown', $event)")
Expand Down Expand Up @@ -48,6 +49,7 @@ interface TextFieldProps {
inputWidth?: string
dbg?: string
default?: string | number
resize?: boolean | string
}

const emit = defineEmits(['update:value', 'blur', 'keydown'])
Expand Down
6 changes: 4 additions & 2 deletions src/components/text-input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
:data-valid="props.valid"
:data-wrong="state.wrongValueAnimation"
:data-width="props.width"
:data-resize="props.resize"
@contextmenu.stop
@mousedown.stop
@mouseup.stop
Expand Down Expand Up @@ -56,6 +57,7 @@ interface TextInputProps {
tabindex?: string
password?: boolean
width?: string
resize?: boolean | string
}

const emit = defineEmits(['update:value', 'focus', 'blur', 'change', 'keydown'])
Expand All @@ -67,7 +69,7 @@ let textareaMinHeight = 0

onMounted(() => {
// Initial textarea height recalc
if (!props.line && textEl.value) {
if (!props.line && !props.resize && textEl.value) {
const prevVal = textEl.value.value
textEl.value.style.height = '0'
textEl.value.value = ' '
Expand Down Expand Up @@ -111,7 +113,7 @@ function onAnimationEnd(): void {
}

function recalcTextHeight(): void {
if (!textEl.value || props.line) return
if (!textEl.value || props.line || props.resize) return
textEl.value.style.height = '0'

const h = textEl.value.scrollHeight - props.padding
Expand Down
10 changes: 10 additions & 0 deletions src/defaults/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const DEFAULT_SETTINGS: SettingsState = {
subPanelBookmarks: true,
subPanelHistory: true,
subPanelSync: false,
subPanelTabSearch: true,

// Group page
groupLayout: 'grid',
Expand Down Expand Up @@ -160,6 +161,14 @@ export const DEFAULT_SETTINGS: SettingsState = {
showNewGroupConf: true,
sortGroupsFirst: true,

// Domain trees
domainTrees: false,
domainTreesUniversal: true,
domainTreeRules: [],
domainTreeNewTabPosition: 'last_child',
domainTreeAutoFold: true,
domainTreeConfirmClose: true,

// Tabs colorization
colorizeTabs: false,
colorizeTabsSrc: 'domain',
Expand Down Expand Up @@ -386,4 +395,5 @@ export const SETTINGS_OPTIONS = {
switchPanelAfterSwitchingTab: ['always', 'mouseleave', 'no'],
scrollPanelAfterSwitchingTab: ['always', 'mouseleave', 'no'],
newTabInPanelPos: ['general', 'btn', 'start', 'end'],
domainTreeNewTabPosition: ['first_child', 'last_child'],
} as const
5 changes: 4 additions & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"author": "mbnuqw",
"name": "__MSG_ExtName__",
"version": "5.6.1",
"version": "5.6.2",
"default_locale": "en",
"description": "__MSG_ExtDesc__",
"homepage_url": "https://github.com/mbnuqw/sidebery",
Expand Down Expand Up @@ -315,6 +315,9 @@
"description": "__MSG_KbMoveTabsToPanelEnd__"
},
"search": {
"suggested_key": {
"default": "F8"
},
"description": "__MSG_KbSearch__"
},
"switch_to_parent_tab": {
Expand Down
47 changes: 47 additions & 0 deletions src/page.group/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ async function main() {
if (favicon) tab.favIconUrl = favicon
}

updateDomainFavicon()

if (pinTab) {
document.body.setAttribute('data-pin', 'true')
document.title = pinTab.title
Expand Down Expand Up @@ -230,6 +232,8 @@ async function onTabCreated(tab: T.GroupedTabInfo) {
Logs.warn('Cannot add new tab: Wrong index:', index)
return
}

updateDomainFavicon()
}

/**
Expand Down Expand Up @@ -269,6 +273,8 @@ function onTabUpdated(upd: T.GroupedTabInfo) {

tab.el.setAttribute('data-lvl', String(upd.lvl))
tab.lvl = upd.lvl

updateDomainFavicon()
}

/**
Expand All @@ -280,11 +286,52 @@ function onTabRemoved(id: ID) {
tabs[index].el?.remove()
tabs.splice(index, 1)

updateDomainFavicon()

if (tabs.length === 0 && window.location.search.includes('pin=')) {
IPPC.bg('tabsApiProxy', 'remove', groupTabId)
}
}

function updateDomainFavicon() {
if (!window.location.search.includes('dt=') || !tabs.length) return
const domainCounts = new Map<string, { count: number; favicon?: string }>()
for (const tab of tabs) {
const domain = getHostname(tab.url)
if (!domain) continue
let entry = domainCounts.get(domain)
if (!entry) {
entry = { count: 0 }
domainCounts.set(domain, entry)
}
entry.count++
if (!entry.favicon && tab.favIconUrl) {
entry.favicon = tab.favIconUrl
}
}

const sorted = Array.from(domainCounts.entries()).sort((a, b) => b[1].count - a[1].count)
let bestFav: string | undefined
for (const [, { favicon }] of sorted) {
if (favicon) {
bestFav = favicon
break
}
}
if (!bestFav) {
for (const tab of tabs) {
if (tab.favIconUrl) {
bestFav = tab.favIconUrl
break
}
}
}
if (bestFav) {
const iconEl = document.querySelector('link[rel="icon"]') as HTMLLinkElement | null
if (iconEl && iconEl.href !== bestFav) iconEl.href = bestFav
}
}

/**
* Create new-tab button
*/
Expand Down
6 changes: 6 additions & 0 deletions src/page.setup/components/settings.navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ section(
dbg="subPanelSync"
:default="DEFAULT_SETTINGS.subPanelSync"
@update:value="Settings.saveDebounced(150)")
ToggleField(
label="settings.sub_panel.tab_search"
v-model:value="Settings.state.subPanelTabSearch"
dbg="subPanelTabSearch"
:default="DEFAULT_SETTINGS.subPanelTabSearch"
@update:value="Settings.saveDebounced(150)")

InfoField(
label="settings.nav_bar_enabled"
Expand Down
Loading