diff --git a/src/_locales/dict.setup-page.ts b/src/_locales/dict.setup-page.ts index 8d91ddcd..e82e48d6 100644 --- a/src/_locales/dict.setup-page.ts +++ b/src/_locales/dict.setup-page.ts @@ -2853,6 +2853,116 @@ Przykłady: "*", "ctrl+$", "ctrl+alt+g"`, zh_TW: '包括輸入新網址的第一次標題更新', ja: '新しいURLの最初のタイトル変更を含む', }, + 'settings.tabs_notification_badge_scope': { + en: 'Show notification badges over tab favicons', + de: 'Benachrichtigungs-Badges auf Tab-Favicons anzeigen', + fr: 'Afficher les badges de notification sur les favicons d\'onglet', + hu: 'Értesítési jelzők megjelenítése a lap ikonjain', + pl: 'Pokaż oznaczenia powiadomień na ikonach kart', + ru: 'Показывать бейджи уведомлений на иконках вкладок', + zh_CN: '在标签页图标上显示通知标记', + zh_TW: '在分頁圖示上顯示通知標記', + ja: 'タブのファビコンに通知バッジを表示する', + }, + 'settings.tabs_notification_badge_scope_all': { + en: 'on', + de: 'Ein', + fr: 'tous', + hu: 'be', + pl: 'włączone', + ru: 'вкл', + zh_CN: '打开', + zh_TW: '開啟', + ja: 'オン', + }, + 'settings.tabs_notification_badge_scope_pin': { + en: 'only for pinned', + de: 'Nur für angeheftete', + fr: 'onglets épinglés seulement', + hu: 'csak rögzített', + pl: 'tylko dla przypiętych', + ru: 'только для закрепленных', + zh_CN: '仅用于固定', + zh_TW: '僅釘選', + ja: '固定のみ', + }, + 'settings.tabs_notification_badge_scope_norm': { + en: 'only for not pinned', + de: 'Nur für nicht angeheftete', + fr: 'onlets non épinglés seulement', + hu: 'csak nem rögzített', + pl: 'tylko dla nieprzypiętych', + ru: 'только для не закрепленных', + zh_CN: '仅用于未固定', + zh_TW: '僅未釘選', + ja: '固定以外のみ', + }, + 'settings.tabs_notification_badge_scope_none': { + en: 'off', + de: 'Aus', + fr: 'aucun', + hu: 'ki', + pl: 'wyłączone', + ru: 'выкл', + zh_CN: '关闭', + zh_TW: '關閉', + ja: 'オフ', + }, + 'settings.tabs_notification_badge_style': { + en: 'Show notification badge with count or a dot', + de: 'Benachrichtigungs-Badge mit Zähler oder Punkt anzeigen', + fr: 'Afficher le badge de notification avec compteur ou point', + hu: 'Értesítési jelző megjelenítése számlálóval vagy ponttal', + pl: 'Pokaż powiadomienie z liczbą lub kropką', + ru: 'Показывать бейдж уведомлений с числом или точкой', + zh_CN: '显示带计数或点的通知标记', + zh_TW: '顯示帶計數或點的通知標記', + ja: '通知バッジをカウントまたはドットで表示する', + }, + 'settings.tabs_notification_badge_style_count': { + en: 'count', + de: 'Zähler', + fr: 'compteur', + hu: 'számláló', + pl: 'licznik', + ru: 'счётчик', + zh_CN: '计数', + zh_TW: '計數', + ja: 'カウント', + }, + 'settings.tabs_notification_badge_style_dot': { + en: 'dot', + de: 'Punkt', + fr: 'point', + hu: 'pont', + pl: 'kropka', + ru: 'точка', + zh_CN: '点', + zh_TW: '點', + ja: 'ドット', + }, + 'settings.tabs_notification_badge_regexp_pattern': { + en: 'Regular expression for matching notification count in tab title', + de: 'Regulärer Ausdruck zur Übereinstimmung der Benachrichtigungszahl im Tab-Titel', + fr: 'Expression régulière pour correspondre au nombre de notifications dans le titre de l\'onglet', + hu: 'Reguláris kifejezés az értesítések számának megfeleltetéséhez a lap címében', + pl: 'Wyrażenie regularne dla dopasowania liczby powiadomień w tytule karty', + ru: 'Регулярное выражение для сопоставления количества уведомлений в заголовке вкладки', + zh_CN: '用于匹配标签页标题中通知数的正则表达式', + zh_TW: '用於匹配分頁標題中通知數的規則運算式', + ja: 'タブのタイトルで通知数をマッチするための正規表現', + }, + 'settings.tabs_notification_badge_regexp_pattern_info': { + en: 'Returns the first found capturing group in the pattern', + de: 'Gibt die erste gefundene Erfassungsgruppe im Muster zurück', + fr: 'Renvoie le premier groupe de capture trouvé dans le motif', + hu: 'Visszaadja a minta első megtalált rögzítő csoportját', + pl: 'Zwraca pierwszą znalezioną grupę przechwytującą we wzorcu', + ru: 'Возвращает первую найденную группу захвата в шаблоне', + zh_CN: '返回模式中找到的第一个捕获组', + zh_TW: '返回模式中找到的第一個捕獲組', + ja: 'パターン内で最初に見つかったキャプチャグループを返します', + }, 'settings.tabs_reload_limit': { en: 'Limit the count of simultaneously reloading tabs', de: 'Beschränke die Anzahl gleichzeitig neu ladender Tabs', diff --git a/src/components/text-field.vue b/src/components/text-field.vue index af288ca3..eb627615 100644 --- a/src/components/text-field.vue +++ b/src/components/text-field.vue @@ -14,6 +14,7 @@ :valid="props.valid" :width="props.inputWidth" @update:value="emit('update:value', $event)" + @blur="onBlur" @keydown="emit('keydown', $event)") .note(v-if="props.note") {{props.note}} @@ -39,7 +40,7 @@ interface TextFieldProps { inputWidth?: string } -const emit = defineEmits(['update:value', 'keydown']) +const emit = defineEmits(['update:value', 'blur', 'keydown']) const props = withDefaults(defineProps(), { padding: 0, tabindex: '0' }) const inputEl = ref(null) @@ -48,6 +49,10 @@ function focus(): void { inputEl.value?.focus() } +function onBlur(): void { + if (inputEl.value) emit('blur', inputEl.value) +} + function error() { inputEl.value?.error() } diff --git a/src/defaults/settings.ts b/src/defaults/settings.ts index 408c8aaf..d2abe7d9 100644 --- a/src/defaults/settings.ts +++ b/src/defaults/settings.ts @@ -84,6 +84,9 @@ export const DEFAULT_SETTINGS: SettingsState = { tabsUnreadMark: false, tabsUpdateMark: 'all', tabsUpdateMarkFirst: true, + tabsNotificationBadgeScope: 'none', + tabsNotificationBadgeStyle: 'count', + tabsNotificationBadgeRegExpPattern: String.raw`\((\d+)\)|\[(\d+)\]`, tabsReloadLimit: 5, tabsReloadLimitNotif: true, showNewTabBtns: true, @@ -310,6 +313,8 @@ export const SETTINGS_OPTIONS = { tabRmBtn: ['always', 'hover', 'none'], activateAfterClosing: ['prev_act', 'next', 'prev', 'none'], tabsUpdateMark: ['all', 'pin', 'norm', 'none'], + tabsNotificationBadgeScope: ['all', 'pin', 'norm', 'none'], + tabsNotificationBadgeStyle: ['count', 'dot'], pinnedTabsPosition: ['panel', 'top', 'left', 'right'], tabsTreeLimit: [1, 2, 3, 4, 5, 'none'], previewTabsMode: ['i', 'p', 'w'], diff --git a/src/page.setup/components/settings.tabs.vue b/src/page.setup/components/settings.tabs.vue index fc3b6e7d..599073ad 100644 --- a/src/page.setup/components/settings.tabs.vue +++ b/src/page.setup/components/settings.tabs.vue @@ -85,6 +85,33 @@ section(ref="el") label="settings.tabs_update_mark_first" v-model:value="Settings.state.tabsUpdateMarkFirst" @update:value="Settings.saveDebounced(150)") + SelectField( + label="settings.tabs_notification_badge_scope" + optLabel="settings.tabs_notification_badge_scope_" + v-model:value="Settings.state.tabsNotificationBadgeScope" + :opts="Settings.getOpts('tabsNotificationBadgeScope')" + :folded="true" + @update:value="Settings.saveDebounced(150)") + .sub-fields + SelectField( + label="settings.tabs_notification_badge_style" + optLabel="settings.tabs_notification_badge_style_" + v-model:value="Settings.state.tabsNotificationBadgeStyle" + :opts="Settings.getOpts('tabsNotificationBadgeStyle')" + :folded="false" + :inactive="Settings.state.tabsNotificationBadgeScope === 'none'" + @update:value="Settings.saveDebounced(150)") + TextField( + ref="tabsNotificationBadgeRegExpPatternEl" + label="settings.tabs_notification_badge_regexp_pattern" + :note="translate('settings.tabs_notification_badge_regexp_pattern_info')" + :line="true" + :valid="tabsNotificationBadgeRegExpPatternValid" + input-width="50" + v-model:value="tabsNotificationBadgeRegExpPatternInput" + :inactive="Settings.state.tabsNotificationBadgeScope === 'none'" + @update:value="onTabsNotificationBadgeRegExpPatternUpdate" + @blur="onTabsNotificationBadgeRegExpPatternBlur") CountField.-inline( label="settings.tabs_reload_limit" v-model:value="Settings.state.tabsReloadLimit" @@ -497,15 +524,18 @@ section(ref="el")