Backgrounds menu tabs (#4845) * Add tabs for backgrounds menu * Improve styling and layout * Use resize observer * Add upload to chat bg logic * Custom BG should always lock * Fix auto-select when deleting active chat bg * Use frame event cancellation on rapid resize * Allow multiple uploads * Fix mobile tab selector * Bypass global lock with shift key * Update copy tooltip * Update localization files

1da6e401297a13f3a490feb7c0f289a819baf66a

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
23 files changed, +318 -93Showing whitespace changes
public/css/backgrounds.css+77 -8
@@ -84,14 +84,6 @@
84 gap: 5px;84 gap: 5px;
85}85}
8686
87#bg-scrollable-content {
88 flex-grow: 1;
89 overflow-y: auto;
90 overflow-x: hidden;
91 padding: 0 5px 15px;
92 position: relative;
93}
94
95#bg_menu_content,87#bg_menu_content,
96#bg_custom_content {88#bg_custom_content {
97 display: grid;89 display: grid;
@@ -301,3 +293,80 @@
301.bg_example:focus-within .BGSampleTitle {293.bg_example:focus-within .BGSampleTitle {
302 opacity: 1;294 opacity: 1;
303}295}
296
297#bg_tabs {
298 display: flex;
299 flex-direction: column;
300 flex-grow: 1;
301 height: 100%;
302 overflow-y: hidden;
303 gap: 5px;
304}
305
306#bg_tabs .bg_tabs_list {
307 display: flex;
308 flex-direction: row;
309 gap: 5px;
310 background: none;
311 border: none;
312 margin: 5px 0;
313 padding: 0;
314 padding-right: 4em;
315 position: relative;
316}
317
318#bg_tabs .bg_tabs_list .bg_tab_button {
319 display: flex;
320 align-items: center;
321 justify-content: center;
322 text-align: center;
323 min-width: 8em;
324 list-style: none;
325 color: var(--SmartThemeBodyColor);
326 background-color: var(--SmartThemeBlurTintColor);
327 border: 1px solid var(--SmartThemeBorderColor);
328 border-radius: 5px;
329 padding: 0;
330 cursor: pointer;
331 font-weight: 600;
332 margin: 0 !important;
333 filter: none;
334 opacity: 0.8;
335 transition: opacity var(--animation-duration-2x);
336}
337
338#bg_tabs .bg_tabs_list .bg_tab_button:hover {
339 opacity: 1;
340}
341
342#bg_tabs .bg_tabs_list .bg_tab_button.ui-tabs-active {
343 background-color: color-mix(in srgb, var(--SmartThemeQuoteColor) 33%, var(--SmartThemeBlurTintColor) 66%);
344}
345
346#bg_tabs.ui-widget-content {
347 border: none !important;
348}
349
350#bg_tabs .bg_tabs_list::before,
351#bg_tabs .bg_tabs_list::after {
352 display: none;
353}
354
355#bg_tabs .bg_tabs_list .bg_tab_button a {
356 width: 100%;
357 height: 100%;
358 padding: 3px 5px;
359 cursor: pointer;
360 color: var(--SmartThemeBodyColor);
361}
362
363#bg_tabs .bg_tab_panel {
364 flex-grow: 1;
365 height: 100%;
366 overflow-y: auto;
367 padding: 10px;
368}
369
370#bg_custom_content:not(:empty)~#bg_chat_hint {
371 display: none;
372}
public/css/mobile-styles.css+4 -0
@@ -97,6 +97,10 @@
97 max-width: 100dvw;97 max-width: 100dvw;
98 }98 }
9999
100 #bg_tabs .bg_tabs_list .bg_tab_button {
101 min-width: 6em;
102 }
103
100 #add_background_button_top>span,104 #add_background_button_top>span,
101 #auto_background>span {105 #auto_background>span {
102 display: none;106 display: none;
public/index.html+16 -14
@@ -5418,11 +5418,14 @@
5418 <input id="bg-filter" class="text_pole" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." />5418 <input id="bg-filter" class="text_pole" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." />
5419 </div>5419 </div>
5420 </div>5420 </div>
5421 <div id="bg-scrollable-content">5421 <div id="bg_tabs" class="heading-container-with-controls">
5422 <div class="heading-container-with-controls">5422 <ul class="bg_tabs_list">
5423 <h3 data-i18n="System Backgrounds" class="wide100p textAlignCenter heading-text">5423 <li class="bg_tab_button">
5424 System Backgrounds5424 <a href="#bg_global_tab" data-i18n="Global">Global</a>
5425 </h3>5425 </li>
5426 <li class="bg_tab_button">
5427 <a href="#bg_chat_tab" data-i18n="Chat">Chat</a>
5428 </li>
5426 <div class="heading-controls">5429 <div class="heading-controls">
5427 <button id="bg_thumb_zoom_out" class="menu_button menu_button_icon" title="Make thumbnails smaller" data-i18n="[title]Make thumbnails smaller">5430 <button id="bg_thumb_zoom_out" class="menu_button menu_button_icon" title="Make thumbnails smaller" data-i18n="[title]Make thumbnails smaller">
5428 <i class="fa-solid fa-minus"></i>5431 <i class="fa-solid fa-minus"></i>
@@ -5431,20 +5434,19 @@
5431 <i class="fa-solid fa-plus"></i>5434 <i class="fa-solid fa-plus"></i>
5432 </button>5435 </button>
5433 </div>5436 </div>
5437 </ul>
5438 <div id="bg_global_tab" class="bg_tab_panel">
5439 <div id="bg_menu_content" class="bg_list"></div>
5434 </div>5440 </div>
5435 <div id="bg_menu_content" class="bg_list">5441 <div id="bg_chat_tab" class="bg_tab_panel">
5436 </div>5442 <div id="bg_custom_content" class="bg_list"></div>
5437 <h3 data-i18n="Chat Backgrounds" class="wide100p textAlignCenter">
5438 Chat Backgrounds
5439 </h3>
5440 <div id="bg_chat_hint" class="wide100p textAlignCenter">5443 <div id="bg_chat_hint" class="wide100p textAlignCenter">
5441 <span data-i18n="bg_chat_hint_1">Chat backgrounds generated with the</span> <code><i class="fa-solid fa-paintbrush"></i>&nbsp;Image Generation</code> <span data-i18n="bg_chat_hint_2">extension will appear here.</span>5444 <span data-i18n="bg_chat_hint_1">Chat backgrounds generated with the</span> <code><i class="fa-solid fa-paintbrush"></i>&nbsp;Image Generation</code> <span data-i18n="bg_chat_hint_2">extension will appear here.</span>
5442 </div>5445 </div>
5443 <div id="bg_custom_content" class="bg_list">
5444 </div>5446 </div>
5445 </div>5447 </div>
5446 <form id="form_bg_upload" style="display: none;">5448 <form id="form_bg_upload" hidden>
5447 <input type="file" id="add_bg_button" name="avatar" accept="image/jpeg,image/png,image/gif,image/bmp,image/svg+xml,video/*">5449 <input type="file" id="add_bg_button" name="avatar" accept="image/*,video/*" multiple hidden>
5448 </form>5450 </form>
5449 <button id="bg-scroll-top" type="button" class="menu_button menu_button_icon" title="Scroll backgrounds to top" data-i18n="[title]Scroll backgrounds to top">5451 <button id="bg-scroll-top" type="button" class="menu_button menu_button_icon" title="Scroll backgrounds to top" data-i18n="[title]Scroll backgrounds to top">
5450 <i class="fa-solid fa-chevron-up" aria-hidden="true"></i>5452 <i class="fa-solid fa-chevron-up" aria-hidden="true"></i>
@@ -6393,7 +6395,7 @@
6393 <div class="jg-menu">6395 <div class="jg-menu">
6394 <div data-action="lock" class="jg-button jg-lock fa-solid fa-lock fa-fw pointer" data-i18n="[title]Lock" title="Lock"></div>6396 <div data-action="lock" class="jg-button jg-lock fa-solid fa-lock fa-fw pointer" data-i18n="[title]Lock" title="Lock"></div>
6395 <div data-action="unlock" class="jg-button jg-unlock fa-solid fa-lock-open fa-fw pointer" data-i18n="[title]Unlock" title="Unlock"></div>6397 <div data-action="unlock" class="jg-button jg-unlock fa-solid fa-lock-open fa-fw pointer" data-i18n="[title]Unlock" title="Unlock"></div>
6396 <div data-action="copy" class="jg-button jg-copy fa-solid fa-file-arrow-up" data-i18n="[title]Copy to system backgrounds" title="Copy to system backgrounds"></div>6398 <div data-action="copy" class="jg-button jg-copy fa-solid fa-file-arrow-up" data-i18n="[title]Copy to global backgrounds" title="Copy to global backgrounds"></div>
6397 <div data-action="edit" class="jg-button jg-edit fa-solid fa-pen-to-square fa-fw pointer" data-i18n="[title]Rename Background" title="Rename Background"></div>6399 <div data-action="edit" class="jg-button jg-edit fa-solid fa-pen-to-square fa-fw pointer" data-i18n="[title]Rename Background" title="Rename Background"></div>
6398 <div data-action="delete" class="jg-button jg-delete fa-solid fa-trash-can fa-fw pointer" data-i18n="[title]Delete Background" title="Delete Background"></div>6400 <div data-action="delete" class="jg-button jg-delete fa-solid fa-trash-can fa-fw pointer" data-i18n="[title]Delete Background" title="Delete Background"></div>
6399 </div>6401 </div>
public/locales/ar-sa.json+3 -3
@@ -739,8 +739,8 @@
739 "Filter": "تصفية",739 "Filter": "تصفية",
740 "Automatically select a background based on the chat context": "تحديد خلفية تلقائيًا استنادًا إلى سياق الدردشة",740 "Automatically select a background based on the chat context": "تحديد خلفية تلقائيًا استنادًا إلى سياق الدردشة",
741 "Auto-select": "التحديد التلقائي",741 "Auto-select": "التحديد التلقائي",
742 "System Backgrounds": "خلفيات النظام",742 "Global": "عالمي",
743 "Chat Backgrounds": "خلفيات الدردشة",743 "Chat": "الدردشة",
744 "bg_chat_hint_1": "خلفيات الدردشة التي تم إنشاؤها باستخدام",744 "bg_chat_hint_1": "خلفيات الدردشة التي تم إنشاؤها باستخدام",
745 "bg_chat_hint_2": "سوف يظهر الامتداد هنا",745 "bg_chat_hint_2": "سوف يظهر الامتداد هنا",
746 "Extensions": "امتدادات",746 "Extensions": "امتدادات",
@@ -913,7 +913,7 @@
913 "Save": "حفظ",913 "Save": "حفظ",
914 "Chat History": "تاريخ الدردشة",914 "Chat History": "تاريخ الدردشة",
915 "Import Chat": "استيراد الدردشة",915 "Import Chat": "استيراد الدردشة",
916 "Copy to system backgrounds": "نسخ إلى خلفيات النظام",916 "Copy to global backgrounds": "نسخ إلى الخلفيات العالمية",
917 "Rename background": "إعادة تسمية الخلفية",917 "Rename background": "إعادة تسمية الخلفية",
918 "Lock": "قفل",918 "Lock": "قفل",
919 "Unlock": "الغاء القفل",919 "Unlock": "الغاء القفل",
public/locales/de-de.json+3 -3
@@ -739,8 +739,8 @@
739 "Filter": "Filter",739 "Filter": "Filter",
740 "Automatically select a background based on the chat context": "Automatisch einen Hintergrund basierend auf dem Chatkontext auswählen",740 "Automatically select a background based on the chat context": "Automatisch einen Hintergrund basierend auf dem Chatkontext auswählen",
741 "Auto-select": "Automatische Auswahl",741 "Auto-select": "Automatische Auswahl",
742 "System Backgrounds": "Systemhintergründe",742 "Global": "Global",
743 "Chat Backgrounds": "Chat-Hintergründe",743 "Chat": "Chat",
744 "bg_chat_hint_1": "Chat-Hintergründe generiert mit dem",744 "bg_chat_hint_1": "Chat-Hintergründe generiert mit dem",
745 "bg_chat_hint_2": "Die Erweiterung wird hier angezeigt.",745 "bg_chat_hint_2": "Die Erweiterung wird hier angezeigt.",
746 "Extensions": "Erweiterungen",746 "Extensions": "Erweiterungen",
@@ -913,7 +913,7 @@
913 "Save": "Speichern",913 "Save": "Speichern",
914 "Chat History": "Chat-Verlauf",914 "Chat History": "Chat-Verlauf",
915 "Import Chat": "Chat importieren",915 "Import Chat": "Chat importieren",
916 "Copy to system backgrounds": "In Systemhintergründe kopieren",916 "Copy to global backgrounds": "In globale Hintergründe kopieren",
917 "Rename background": "Hintergrund umbenennen",917 "Rename background": "Hintergrund umbenennen",
918 "Lock": "Sperren",918 "Lock": "Sperren",
919 "Unlock": "Freischalten",919 "Unlock": "Freischalten",
public/locales/es-es.json+3 -3
@@ -739,8 +739,8 @@
739 "Filter": "Filtro",739 "Filter": "Filtro",
740 "Automatically select a background based on the chat context": "Seleccionar automáticamente un fondo basado en el contexto del chat",740 "Automatically select a background based on the chat context": "Seleccionar automáticamente un fondo basado en el contexto del chat",
741 "Auto-select": "Auto-seleccionar",741 "Auto-select": "Auto-seleccionar",
742 "System Backgrounds": "Fondos del Sistema",742 "Global": "Global",
743 "Chat Backgrounds": "Fondos de Chat",743 "Chat": "Chat",
744 "bg_chat_hint_1": "Fondos de chat generados con el",744 "bg_chat_hint_1": "Fondos de chat generados con el",
745 "bg_chat_hint_2": "La extensión aparecerá aquí.",745 "bg_chat_hint_2": "La extensión aparecerá aquí.",
746 "Extensions": "Extensiones",746 "Extensions": "Extensiones",
@@ -913,7 +913,7 @@
913 "Save": "Guardar",913 "Save": "Guardar",
914 "Chat History": "Historial de chat",914 "Chat History": "Historial de chat",
915 "Import Chat": "Importar chat",915 "Import Chat": "Importar chat",
916 "Copy to system backgrounds": "Copiar a fondos del sistema",916 "Copy to global backgrounds": "Copiar a fondos globales",
917 "Rename background": "Cambiar nombre de fondo",917 "Rename background": "Cambiar nombre de fondo",
918 "Lock": "Cerrar",918 "Lock": "Cerrar",
919 "Unlock": "desbloquear",919 "Unlock": "desbloquear",
public/locales/fr-fr.json+3 -3
@@ -684,8 +684,8 @@
684 "Filter": "Filtre",684 "Filter": "Filtre",
685 "Automatically select a background based on the chat context": "Sélectionner automatiquement un arrière-plan en fonction du contexte de la discussion",685 "Automatically select a background based on the chat context": "Sélectionner automatiquement un arrière-plan en fonction du contexte de la discussion",
686 "Auto-select": "Sélection automatique",686 "Auto-select": "Sélection automatique",
687 "System Backgrounds": "Arrière-plans du système",687 "Global": "Global",
688 "Chat Backgrounds": "Arrière-plans de la discussion",688 "Chat": "Discussion",
689 "bg_chat_hint_1": "Les arrière-plans générés avec l'extension ",689 "bg_chat_hint_1": "Les arrière-plans générés avec l'extension ",
690 "bg_chat_hint_2": " apparaîtrons ici.",690 "bg_chat_hint_2": " apparaîtrons ici.",
691 "Extensions": "Extensions",691 "Extensions": "Extensions",
@@ -856,7 +856,7 @@
856 "Save": "Enregistrer",856 "Save": "Enregistrer",
857 "Chat History": "Historique de la conversation",857 "Chat History": "Historique de la conversation",
858 "Import Chat": "Importer une discussion",858 "Import Chat": "Importer une discussion",
859 "Copy to system backgrounds": "Copier vers les arrière-plans du système",859 "Copy to global backgrounds": "Copier vers les arrière-plans globaux",
860 "Rename background": "Renommer l'arrière-plan",860 "Rename background": "Renommer l'arrière-plan",
861 "Lock": "Verrouiller",861 "Lock": "Verrouiller",
862 "Unlock": "Déverrouiller",862 "Unlock": "Déverrouiller",
public/locales/is-is.json+3 -3
@@ -737,8 +737,8 @@
737 "Filter": "Sía",737 "Filter": "Sía",
738 "Automatically select a background based on the chat context": "Velja sjálfkrafa bakgrunn út frá samhengi spjallsins",738 "Automatically select a background based on the chat context": "Velja sjálfkrafa bakgrunn út frá samhengi spjallsins",
739 "Auto-select": "Sjálfval",739 "Auto-select": "Sjálfval",
740 "System Backgrounds": "Kerfis bakgrunnsmyndir",740 "Global": "Almennt",
741 "Chat Backgrounds": "Bakgrunnsmyndir spjalls",741 "Chat": "Spjall",
742 "bg_chat_hint_1": "Spjallbakgrunnur myndaður með",742 "bg_chat_hint_1": "Spjallbakgrunnur myndaður með",
743 "bg_chat_hint_2": "viðbót mun birtast hér.",743 "bg_chat_hint_2": "viðbót mun birtast hér.",
744 "Extensions": "Viðbætur",744 "Extensions": "Viðbætur",
@@ -911,7 +911,7 @@
911 "Save": "Vista",911 "Save": "Vista",
912 "Chat History": "Spjall saga",912 "Chat History": "Spjall saga",
913 "Import Chat": "Flytja inn spjall",913 "Import Chat": "Flytja inn spjall",
914 "Copy to system backgrounds": "Afritaðu í kerfisbakgrunn",914 "Copy to global backgrounds": "Afritaðu í alþjóðlegan bakgrunn",
915 "Rename background": "Endurnefna bakgrunn",915 "Rename background": "Endurnefna bakgrunn",
916 "Lock": "Læsa",916 "Lock": "Læsa",
917 "Unlock": "Opnaðu",917 "Unlock": "Opnaðu",
public/locales/it-it.json+3 -3
@@ -739,8 +739,8 @@
739 "Filter": "Filtro",739 "Filter": "Filtro",
740 "Automatically select a background based on the chat context": "Seleziona automaticamente uno sfondo in base al contesto della chat",740 "Automatically select a background based on the chat context": "Seleziona automaticamente uno sfondo in base al contesto della chat",
741 "Auto-select": "Selezione automatica",741 "Auto-select": "Selezione automatica",
742 "System Backgrounds": "Sfondi di sistema",742 "Global": "Globale",
743 "Chat Backgrounds": "Sfondi Chat",743 "Chat": "Chat",
744 "bg_chat_hint_1": "Sfondi chat generati con",744 "bg_chat_hint_1": "Sfondi chat generati con",
745 "bg_chat_hint_2": "l'estensione apparirà qui.",745 "bg_chat_hint_2": "l'estensione apparirà qui.",
746 "Extensions": "Estensioni",746 "Extensions": "Estensioni",
@@ -913,7 +913,7 @@
913 "Save": "Salva",913 "Save": "Salva",
914 "Chat History": "Cronologia Chat",914 "Chat History": "Cronologia Chat",
915 "Import Chat": "Importa chat",915 "Import Chat": "Importa chat",
916 "Copy to system backgrounds": "Copia negli sfondi di sistema",916 "Copy to global backgrounds": "Copia negli sfondi globali",
917 "Rename background": "Rinominare lo sfondo",917 "Rename background": "Rinominare lo sfondo",
918 "Lock": "Serratura",918 "Lock": "Serratura",
919 "Unlock": "Sbloccare",919 "Unlock": "Sbloccare",
public/locales/ja-jp.json+3 -3
@@ -739,8 +739,8 @@
739 "Filter": "フィルター",739 "Filter": "フィルター",
740 "Automatically select a background based on the chat context": "チャットのコンテキストに基づいて背景を自動選択",740 "Automatically select a background based on the chat context": "チャットのコンテキストに基づいて背景を自動選択",
741 "Auto-select": "自動選択",741 "Auto-select": "自動選択",
742 "System Backgrounds": "システムの背景",742 "Global": "グローバル",
743 "Chat Backgrounds": "チャットの背景",743 "Chat": "チャット",
744 "bg_chat_hint_1": "",744 "bg_chat_hint_1": "",
745 "bg_chat_hint_2": "拡張機能で生成したチャットの背景はここに表示されます。",745 "bg_chat_hint_2": "拡張機能で生成したチャットの背景はここに表示されます。",
746 "Extensions": "拡張機能",746 "Extensions": "拡張機能",
@@ -913,7 +913,7 @@
913 "Save": "保存",913 "Save": "保存",
914 "Chat History": "チャット履歴",914 "Chat History": "チャット履歴",
915 "Import Chat": "チャットをインポート",915 "Import Chat": "チャットをインポート",
916 "Copy to system backgrounds": "システム背景にコピー",916 "Copy to global backgrounds": "グローバル背景にコピー",
917 "Rename background": "背景の名前を変更",917 "Rename background": "背景の名前を変更",
918 "Lock": "ロック",918 "Lock": "ロック",
919 "Unlock": "ロック解除",919 "Unlock": "ロック解除",
public/locales/ko-kr.json+3 -3
@@ -752,8 +752,8 @@
752 "Filter": "필터",752 "Filter": "필터",
753 "Automatically select a background based on the chat context": "채팅 컨텍스트를 기반으로 자동으로 배경 선택",753 "Automatically select a background based on the chat context": "채팅 컨텍스트를 기반으로 자동으로 배경 선택",
754 "Auto-select": "자동 선택",754 "Auto-select": "자동 선택",
755 "System Backgrounds": "시스템 배경",755 "Global": "글로벌",
756 "Chat Backgrounds": "채팅 배경",756 "Chat": "채팅",
757 "bg_chat_hint_1": "다음으로 생성된 채팅 배경",757 "bg_chat_hint_1": "다음으로 생성된 채팅 배경",
758 "bg_chat_hint_2": "확장 프로그램이 여기에 표시됩니다.",758 "bg_chat_hint_2": "확장 프로그램이 여기에 표시됩니다.",
759 "Extensions": "확장",759 "Extensions": "확장",
@@ -927,7 +927,7 @@
927 "Save": "저장",927 "Save": "저장",
928 "Chat History": "채팅 기록",928 "Chat History": "채팅 기록",
929 "Import Chat": "채팅 가져오기",929 "Import Chat": "채팅 가져오기",
930 "Copy to system backgrounds": "시스템 배경에 복사",930 "Copy to global backgrounds": "글로벌 배경에 복사",
931 "Rename background": "배경 이름 바꾸기",931 "Rename background": "배경 이름 바꾸기",
932 "Lock": "잠금",932 "Lock": "잠금",
933 "Unlock": "잠금 해제",933 "Unlock": "잠금 해제",
public/locales/nl-nl.json+3 -3
@@ -735,8 +735,8 @@
735 "Filter": "Filter",735 "Filter": "Filter",
736 "Automatically select a background based on the chat context": "Automatisch een achtergrond selecteren op basis van de chatcontext",736 "Automatically select a background based on the chat context": "Automatisch een achtergrond selecteren op basis van de chatcontext",
737 "Auto-select": "Automatisch selecteren",737 "Auto-select": "Automatisch selecteren",
738 "System Backgrounds": "Systeemachtergronden",738 "Global": "Globaal",
739 "Chat Backgrounds": "Achtergronden chat",739 "Chat": "Chat",
740 "bg_chat_hint_1": "Chatachtergronden gegenereerd met de",740 "bg_chat_hint_1": "Chatachtergronden gegenereerd met de",
741 "bg_chat_hint_2": "extensie zal hier verschijnen.",741 "bg_chat_hint_2": "extensie zal hier verschijnen.",
742 "Extensions": "Uitbreidingen",742 "Extensions": "Uitbreidingen",
@@ -909,7 +909,7 @@
909 "Save": "Opslaan",909 "Save": "Opslaan",
910 "Chat History": "Chatgeschiedenis",910 "Chat History": "Chatgeschiedenis",
911 "Import Chat": "Chat importeren",911 "Import Chat": "Chat importeren",
912 "Copy to system backgrounds": "Kopiëren naar systeemachtergronden",912 "Copy to global backgrounds": "Kopiëren naar globale achtergronden",
913 "Rename background": "Achtergrond hernoemen",913 "Rename background": "Achtergrond hernoemen",
914 "Lock": "Slot",914 "Lock": "Slot",
915 "Unlock": "Ontgrendelen",915 "Unlock": "Ontgrendelen",
public/locales/pt-pt.json+3 -3
@@ -737,8 +737,8 @@
737 "Filter": "Filtro",737 "Filter": "Filtro",
738 "Automatically select a background based on the chat context": "Selecionar automaticamente um plano de fundo com base no contexto do chat",738 "Automatically select a background based on the chat context": "Selecionar automaticamente um plano de fundo com base no contexto do chat",
739 "Auto-select": "Seleção automática",739 "Auto-select": "Seleção automática",
740 "System Backgrounds": "Fundos do Sistema",740 "Global": "Global",
741 "Chat Backgrounds": "Fundos de Chat",741 "Chat": "Chat",
742 "bg_chat_hint_1": "Planos de fundo de bate-papo gerados com o",742 "bg_chat_hint_1": "Planos de fundo de bate-papo gerados com o",
743 "bg_chat_hint_2": "a extensão aparecerá aqui.",743 "bg_chat_hint_2": "a extensão aparecerá aqui.",
744 "Extensions": "Extensões",744 "Extensions": "Extensões",
@@ -911,7 +911,7 @@
911 "Save": "Salvar",911 "Save": "Salvar",
912 "Chat History": "Histórico de Chat",912 "Chat History": "Histórico de Chat",
913 "Import Chat": "Importar bate-papo",913 "Import Chat": "Importar bate-papo",
914 "Copy to system backgrounds": "Copiar para planos de fundo do sistema",914 "Copy to global backgrounds": "Copiar para planos de fundo globais",
915 "Rename background": "Renomear plano de fundo",915 "Rename background": "Renomear plano de fundo",
916 "Lock": "Trancar",916 "Lock": "Trancar",
917 "Unlock": "Desbloquear",917 "Unlock": "Desbloquear",
public/locales/ru-ru.json+2 -3
@@ -244,7 +244,6 @@
244 "Always include examples": "Всегда применять примеры",244 "Always include examples": "Всегда применять примеры",
245 "Never include examples": "Никогда не применять примеры",245 "Never include examples": "Никогда не применять примеры",
246 "Forbid External Media": "Запрет внешних медиа",246 "Forbid External Media": "Запрет внешних медиа",
247 "System Backgrounds": "Системные фоны",
248 "Name": "Имя",247 "Name": "Имя",
249 "Auto-connect": "Подключаться автоматически",248 "Auto-connect": "Подключаться автоматически",
250 "First message": "Первое сообщение",249 "First message": "Первое сообщение",
@@ -350,7 +349,7 @@
350 "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.",349 "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.",
351 "User Message Blur Tint": "Ваши сообщения",350 "User Message Blur Tint": "Ваши сообщения",
352 "AI Message Blur Tint": "Сообщения ИИ",351 "AI Message Blur Tint": "Сообщения ИИ",
353 "Chat Backgrounds": "Фоны чата",352 "Chat": "Чат",
354 "Chat Background": "Фон чата",353 "Chat Background": "Фон чата",
355 "UI Background": "Фон UI",354 "UI Background": "Фон UI",
356 "Mad Lab Mode": "Режим безумца",355 "Mad Lab Mode": "Режим безумца",
@@ -1326,7 +1325,7 @@
1326 "Auto Mode delay": "Auto Mode delay",1325 "Auto Mode delay": "Auto Mode delay",
1327 "Bulk_edit_characters": "Bulk edit characters\r\rClick to toggle characters\rShift + Click to select/deselect a range of characters\rRight-click for actions",1326 "Bulk_edit_characters": "Bulk edit characters\r\rClick to toggle characters\rShift + Click to select/deselect a range of characters\rRight-click for actions",
1328 "Bulk select all characters": "Bulk select all characters",1327 "Bulk select all characters": "Bulk select all characters",
1329 "Copy to system backgrounds": "Copy to system backgrounds",1328 "Copy to global backgrounds": "Скопировать в глобальные фоны",
1330 "Chat Scenario Override": "Chat Scenario Override",1329 "Chat Scenario Override": "Chat Scenario Override",
1331 "Chat Lorebook": "Chat Lorebook for",1330 "Chat Lorebook": "Chat Lorebook for",
1332 "chat_world_template_txt": "A selected World Info will be bound to this chat. When generating an AI reply,\n it will be combined with the entries from global and character lorebooks.",1331 "chat_world_template_txt": "A selected World Info will be bound to this chat. When generating an AI reply,\n it will be combined with the entries from global and character lorebooks.",
public/locales/th-th.json+3 -3
@@ -745,8 +745,8 @@
745 "Filter": "ตัวกรอง",745 "Filter": "ตัวกรอง",
746 "Automatically select a background based on the chat context": "เลือกพื้นหลังโดยอัตโนมัติตามบริบทของแชท",746 "Automatically select a background based on the chat context": "เลือกพื้นหลังโดยอัตโนมัติตามบริบทของแชท",
747 "Auto-select": "เลือกอัตโนมัติ",747 "Auto-select": "เลือกอัตโนมัติ",
748 "System Backgrounds": "พื้นหลังของระบบ",748 "Global": "ทั่วโลก",
749 "Chat Backgrounds": "พื้นหลังแชท",749 "Chat": "แชท",
750 "bg_chat_hint_1": "พื้นหลังของแชทที่ถูกสร้างด้วย",750 "bg_chat_hint_1": "พื้นหลังของแชทที่ถูกสร้างด้วย",
751 "bg_chat_hint_2": "จะปรากฏที่นี่",751 "bg_chat_hint_2": "จะปรากฏที่นี่",
752 "Extensions": "โปรแกรมส่วนขยาย",752 "Extensions": "โปรแกรมส่วนขยาย",
@@ -921,7 +921,7 @@
921 "Save": "บันทึก",921 "Save": "บันทึก",
922 "Chat History": "ประวัติการแชท",922 "Chat History": "ประวัติการแชท",
923 "Import Chat": "นำเข้าไฟล์แชท",923 "Import Chat": "นำเข้าไฟล์แชท",
924 "Copy to system backgrounds": "คัดลอกไปยังพื้นหลัง",924 "Copy to global backgrounds": "คัดลอกไปยังพื้นหลังทั่วโลก",
925 "Rename background": "เปลี่ยนชื่อพื้นหลัง",925 "Rename background": "เปลี่ยนชื่อพื้นหลัง",
926 "Lock": "ล็อค",926 "Lock": "ล็อค",
927 "Unlock": "ปลดล็อค",927 "Unlock": "ปลดล็อค",
public/locales/uk-ua.json+3 -3
@@ -737,8 +737,8 @@
737 "Filter": "Фільтр",737 "Filter": "Фільтр",
738 "Automatically select a background based on the chat context": "Автоматичний вибір фону на основі контексту чату",738 "Automatically select a background based on the chat context": "Автоматичний вибір фону на основі контексту чату",
739 "Auto-select": "Автовибір",739 "Auto-select": "Автовибір",
740 "System Backgrounds": "Системні фони",740 "Global": "Глобальні",
741 "Chat Backgrounds": "Фони чату",741 "Chat": "Чат",
742 "bg_chat_hint_1": "Фонове зображення чату, створене за допомогою",742 "bg_chat_hint_1": "Фонове зображення чату, створене за допомогою",
743 "bg_chat_hint_2": "тут з’явиться розширення.",743 "bg_chat_hint_2": "тут з’явиться розширення.",
744 "Extensions": "Розширення",744 "Extensions": "Розширення",
@@ -911,7 +911,7 @@
911 "Save": "Зберегти",911 "Save": "Зберегти",
912 "Chat History": "Історія чату",912 "Chat History": "Історія чату",
913 "Import Chat": "Імпорт чату",913 "Import Chat": "Імпорт чату",
914 "Copy to system backgrounds": "Скопіювати в системні фони",914 "Copy to global backgrounds": "Скопіювати в глобальні фони",
915 "Rename background": "Перейменувати фон",915 "Rename background": "Перейменувати фон",
916 "Lock": "Замок",916 "Lock": "Замок",
917 "Unlock": "Розблокувати",917 "Unlock": "Розблокувати",
public/locales/vi-vn.json+3 -3
@@ -737,8 +737,8 @@
737 "Filter": "Bộ lọc",737 "Filter": "Bộ lọc",
738 "Automatically select a background based on the chat context": "Tự động chọn một nền dựa trên context trò chuyện",738 "Automatically select a background based on the chat context": "Tự động chọn một nền dựa trên context trò chuyện",
739 "Auto-select": "Tự động chọn",739 "Auto-select": "Tự động chọn",
740 "System Backgrounds": "Nền Hệ thống",740 "Global": "Toàn cầu",
741 "Chat Backgrounds": "Hình nền Chat",741 "Chat": "Trò chuyện",
742 "bg_chat_hint_1": "Hình nền trò chuyện được tạo bằng",742 "bg_chat_hint_1": "Hình nền trò chuyện được tạo bằng",
743 "bg_chat_hint_2": "tiện ích sẽ xuất hiện ở đây.",743 "bg_chat_hint_2": "tiện ích sẽ xuất hiện ở đây.",
744 "Extensions": "Tiện ích",744 "Extensions": "Tiện ích",
@@ -911,7 +911,7 @@
911 "Save": "Lưu",911 "Save": "Lưu",
912 "Chat History": "Lịch sử Trò chuyện",912 "Chat History": "Lịch sử Trò chuyện",
913 "Import Chat": "Nhập trò chuyện",913 "Import Chat": "Nhập trò chuyện",
914 "Copy to system backgrounds": "Sao chép vào nền hệ thống",914 "Copy to global backgrounds": "Sao chép vào nền toàn cầu",
915 "Rename background": "Đổi tên nền background",915 "Rename background": "Đổi tên nền background",
916 "Lock": "Khóa",916 "Lock": "Khóa",
917 "Unlock": "Mở khóa",917 "Unlock": "Mở khóa",
public/locales/zh-cn.json+2 -3
@@ -961,8 +961,7 @@
961 "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景",961 "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景",
962 "Auto-select": "自动选择",962 "Auto-select": "自动选择",
963 "Add Background": "添加背景",963 "Add Background": "添加背景",
964 "System Backgrounds": "系统背景",964 "Global": "全局",
965 "Chat Backgrounds": "聊天背景",
966 "bg_chat_hint_1": "使用生成的聊天背景",965 "bg_chat_hint_1": "使用生成的聊天背景",
967 "bg_chat_hint_2": "扩展名将出现在这里。",966 "bg_chat_hint_2": "扩展名将出现在这里。",
968 "Extensions": "扩展",967 "Extensions": "扩展",
@@ -1157,7 +1156,7 @@
1157 "Save": "保存",1156 "Save": "保存",
1158 "Chat History": "聊天记录",1157 "Chat History": "聊天记录",
1159 "Import Chat": "导入聊天",1158 "Import Chat": "导入聊天",
1160 "Copy to system backgrounds": "复制到系统背景",1159 "Copy to global backgrounds": "复制到全局背景",
1161 "Lock": "锁定",1160 "Lock": "锁定",
1162 "Unlock": "解锁",1161 "Unlock": "解锁",
1163 "Rename Background": "重命名背景",1162 "Rename Background": "重命名背景",
public/locales/zh-tw.json+2 -3
@@ -736,8 +736,7 @@
736 "Filter": "篩選",736 "Filter": "篩選",
737 "Automatically select a background based on the chat context": "根據聊天上下文自動選擇背景",737 "Automatically select a background based on the chat context": "根據聊天上下文自動選擇背景",
738 "Auto-select": "自動選擇",738 "Auto-select": "自動選擇",
739 "System Backgrounds": "系統背景圖片",739 "Global": "全域",
740 "Chat Backgrounds": "聊天背景圖片",
741 "bg_chat_hint_1": "使用擴充功能",740 "bg_chat_hint_1": "使用擴充功能",
742 "bg_chat_hint_2": "所產生的背景圖片將在此顯示。",741 "bg_chat_hint_2": "所產生的背景圖片將在此顯示。",
743 "Extensions": "擴充功能",742 "Extensions": "擴充功能",
@@ -909,7 +908,7 @@
909 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天對話範例。每個範例以新的行並以「START」開始。)",908 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天對話範例。每個範例以新的行並以「START」開始。)",
910 "Chat History": "聊天記錄",909 "Chat History": "聊天記錄",
911 "Import Chat": "匯入聊天",910 "Import Chat": "匯入聊天",
912 "Copy to system backgrounds": "複製到系統背景圖片",911 "Copy to global backgrounds": "複製到全局背景圖片",
913 "Rename background": "重新命名背景圖片",912 "Rename background": "重新命名背景圖片",
914 "Lock": "上鎖",913 "Lock": "上鎖",
915 "Unlock": "解鎖",914 "Unlock": "解鎖",
public/scripts/a11y.js+14 -0
@@ -50,6 +50,14 @@ const toolbarSelectors = [
50 '.jg-menu',50 '.jg-menu',
51].join(', ');51].join(', ');
5252
53const tabListSelectors = [
54 '#bg_tabs .bg_tabs_list',
55].join(', ');
56
57const tabItemSelectors = [
58 '#bg_tabs .bg_tabs_list .bg_tab_button',
59].join(', ');
60
53/** @type {Record<string, (element: Element) => void>} */61/** @type {Record<string, (element: Element) => void>} */
54const a11yRules = {62const a11yRules = {
55 [buttonSelectors]: (element) => {63 [buttonSelectors]: (element) => {
@@ -64,6 +72,12 @@ const a11yRules = {
64 [toolbarSelectors]: (element) => {72 [toolbarSelectors]: (element) => {
65 element.setAttribute('role', 'toolbar');73 element.setAttribute('role', 'toolbar');
66 },74 },
75 [tabListSelectors]: (element) => {
76 element.setAttribute('role', 'tablist');
77 },
78 [tabItemSelectors]: (element) => {
79 element.setAttribute('role', 'tab');
80 },
67 '#toast-container .toast': (element) => {81 '#toast-container .toast': (element) => {
68 element.setAttribute('role', 'status');82 element.setAttribute('role', 'status');
69 },83 },
public/scripts/backgrounds.js+149 -23
@@ -1,12 +1,15 @@
1import { Fuse, localforage } from '../lib.js';1import { Fuse, localforage } from '../lib.js';
2import { chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveSettingsDebounced } from '../script.js';2import { characters, chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveMetadata, saveSettingsDebounced, this_chid } from '../script.js';
3import { openThirdPartyExtensionMenu, saveMetadataDebounced } from './extensions.js';3import { openThirdPartyExtensionMenu, saveMetadataDebounced } from './extensions.js';
4import { SlashCommand } from './slash-commands/SlashCommand.js';4import { SlashCommand } from './slash-commands/SlashCommand.js';
5import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';5import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
6import { createThumbnail, flashHighlight, getBase64Async, stringFormat, debounce, setupScrollToTop } from './utils.js';6import { createThumbnail, flashHighlight, getBase64Async, stringFormat, debounce, setupScrollToTop, saveBase64AsFile, getFileExtension } from './utils.js';
7import { debounce_timeout } from './constants.js';7import { debounce_timeout } from './constants.js';
8import { t } from './i18n.js';8import { t } from './i18n.js';
9import { Popup } from './popup.js';9import { Popup } from './popup.js';
10import { groups, selected_group } from './group-chats.js';
11import { humanizedDateTime } from './RossAscends-mods.js';
12import { deleteMediaFromServer } from './chats.js';
1013
11const BG_METADATA_KEY = 'custom_background';14const BG_METADATA_KEY = 'custom_background';
12const LIST_METADATA_KEY = 'chat_backgrounds';15const LIST_METADATA_KEY = 'chat_backgrounds';
@@ -39,6 +42,26 @@ const THUMBNAIL_CONFIG = {
39};42};
4043
41/**44/**
45 * Background source types.
46 * @readonly
47 * @enum {number}
48 */
49const BG_SOURCES = {
50 GLOBAL: 0,
51 CHAT: 1,
52};
53
54/**
55 * Mapping of background sources to their corresponding tab IDs.
56 * @readonly
57 * @type {Record<string, string>}
58 */
59const BG_TABS = Object.freeze({
60 [BG_SOURCES.GLOBAL]: 'bg_global_tab',
61 [BG_SOURCES.CHAT]: 'bg_chat_tab',
62});
63
64/**
42 * Global IntersectionObserver instance for lazy loading backgrounds65 * Global IntersectionObserver instance for lazy loading backgrounds
43 * @type {IntersectionObserver|null}66 * @type {IntersectionObserver|null}
44 */67 */
@@ -187,6 +210,7 @@ function onLockBackgroundClick(event = null) {
187210
188 // Update UI states to reflect the new lock.211 // Update UI states to reflect the new lock.
189 highlightLockedBackground();212 highlightLockedBackground();
213 highlightSelectedBackground();
190}214}
191215
192/**216/**
@@ -219,21 +243,27 @@ function removeBackgroundMetadata() {
219 saveMetadataDebounced();243 saveMetadataDebounced();
220}244}
221245
222function onSelectBackgroundClick() {246/**
247 * Handles the click event for selecting a background.
248 * @param {JQuery.Event} e Event
249 */
250function onSelectBackgroundClick(e) {
223 const bgFile = $(this).attr('bgfile');251 const bgFile = $(this).attr('bgfile');
252 const isCustom = $(this).attr('custom') === 'true';
224 const backgroundCssUrl = getUrlParameter(this);253 const backgroundCssUrl = getUrlParameter(this);
254 const bypassGlobalLock = !isCustom && e.shiftKey;
225255
226 if (isChatBackgroundLocked()) {256 if ((isChatBackgroundLocked() || isCustom) && !bypassGlobalLock) {
227 // If a background is locked, update the locked background directly257 // If a background is locked, update the locked background directly
228 saveBackgroundMetadata(backgroundCssUrl);258 saveBackgroundMetadata(backgroundCssUrl);
229 $('#bg1').css('background-image', backgroundCssUrl);259 $('#bg1').css('background-image', backgroundCssUrl);
230 highlightLockedBackground();
231 } else {260 } else {
232 // Otherwise, update the global background setting261 // Otherwise, update the global background setting
233 setBackground(bgFile, backgroundCssUrl);262 setBackground(bgFile, backgroundCssUrl);
234 }263 }
235264
236 // Update UI highlights to reflect the changes.265 // Update UI highlights to reflect the changes.
266 highlightLockedBackground();
237 highlightSelectedBackground();267 highlightSelectedBackground();
238}268}
239269
@@ -375,20 +405,37 @@ async function onDeleteBackgroundClick(e) {
375 const bgToDelete = $(this).closest('.bg_example');405 const bgToDelete = $(this).closest('.bg_example');
376 const url = bgToDelete.data('url');406 const url = bgToDelete.data('url');
377 const isCustom = bgToDelete.attr('custom') === 'true';407 const isCustom = bgToDelete.attr('custom') === 'true';
378 const confirm = await Popup.show.confirm(t`Delete the background?`, null);408 const deleteFromServerId = 'delete_bg_from_server';
409 const customInputs = [
410 {
411 type: 'checkbox',
412 label: t`Also delete file from server`,
413 id: deleteFromServerId,
414 defaultState: true,
415 },
416 ];
417 let deleteFromServer = false;
418 const confirm = await Popup.show.confirm(t`Delete the background?`, null, {
419 customInputs: isCustom ? customInputs : [],
420 onClose: (popup) => {
421 if (isCustom) {
422 deleteFromServer = Boolean(popup?.inputResults?.get(deleteFromServerId) ?? false);
423 }
424 },
425 });
379 const bg = bgToDelete.attr('bgfile');426 const bg = bgToDelete.attr('bgfile');
380427
381 if (confirm) {428 if (confirm) {
382 // If it's not custom, it's a built-in background. Delete it from the server429 // If it's not custom, it's a built-in background. Delete it from the server
383 if (!isCustom) {430 if (!isCustom) {
384 delBackground(bg);431 await delBackground(bg);
385 } else {432 } else {
386 const list = chat_metadata[LIST_METADATA_KEY] || [];433 const list = chat_metadata[LIST_METADATA_KEY] || [];
387 const index = list.indexOf(bg);434 const index = list.indexOf(bg);
388 list.splice(index, 1);435 list.splice(index, 1);
389 }436 }
390437
391 if (bg === background_settings.name) {438 if (bg === background_settings.name || url === chat_metadata[BG_METADATA_KEY]) {
392 const siblingSelector = '.bg_example';439 const siblingSelector = '.bg_example';
393 const nextBg = bgToDelete.next(siblingSelector);440 const nextBg = bgToDelete.next(siblingSelector);
394 const prevBg = bgToDelete.prev(siblingSelector);441 const prevBg = bgToDelete.prev(siblingSelector);
@@ -409,13 +456,18 @@ async function onDeleteBackgroundClick(e) {
409456
410 if (url === chat_metadata[BG_METADATA_KEY]) {457 if (url === chat_metadata[BG_METADATA_KEY]) {
411 removeBackgroundMetadata();458 removeBackgroundMetadata();
412 highlightLockedBackground();
413 }459 }
414460
415 if (isCustom) {461 if (isCustom) {
462 if (deleteFromServer) {
463 await deleteMediaFromServer(bg);
464 }
416 renderChatBackgrounds();465 renderChatBackgrounds();
417 saveMetadataDebounced();466 await saveMetadata();
418 }467 }
468
469 highlightLockedBackground();
470 highlightSelectedBackground();
419 }471 }
420}472}
421473
@@ -607,25 +659,43 @@ async function delBackground(bg) {
607 }659 }
608}660}
609661
610async function onBackgroundUploadSelected() {662/**
611 const form = $('#form_bg_upload').get(0);663 * Background upload handler.
664 * @param {Event} e Event
665 * @returns {Promise<void>}
666 */
667async function onBackgroundUploadSelected(e) {
668 const input = e.currentTarget;
612669
613 if (!(form instanceof HTMLFormElement)) {670 if (!(input instanceof HTMLInputElement)) {
614 console.error('form_bg_upload is not a form');671 console.error('Invalid input element for background upload');
615 return;672 return;
616 }673 }
617674
618 const formData = new FormData(form);675 for (const file of input.files) {
619676 if (file.size === 0) {
620 const file = formData.get('avatar');677 continue;
621 if (!(file instanceof File) || file.size === 0) {
622 form.reset();
623 return;
624 }678 }
625679
680 const formData = new FormData();
681 formData.append('avatar', file);
682
626 await convertFileIfVideo(formData);683 await convertFileIfVideo(formData);
684 switch (getActiveBackgroundTab()) {
685 case BG_SOURCES.GLOBAL:
627 await uploadBackground(formData);686 await uploadBackground(formData);
628 form.reset();687 break;
688 case BG_SOURCES.CHAT:
689 await uploadChatBackground(formData);
690 break;
691 default:
692 console.error('Unknown background source type');
693 continue;
694 }
695 }
696
697 // Allow re-uploading the same file again by clearing the input value
698 input.value = '';
629}699}
630700
631/**701/**
@@ -699,6 +769,50 @@ async function uploadBackground(formData) {
699}769}
700770
701/**771/**
772 * Upload a chat background using a FormData object.
773 * @param {FormData} formData FormData containing the background file
774 * @returns {Promise<void>}
775 */
776async function uploadChatBackground(formData) {
777 try {
778 if (!getCurrentChatId()) {
779 toastr.warning(t`Select a chat to upload a background for it`);
780 return;
781 }
782 if (!formData.has('avatar')) {
783 console.log('No file provided. Chat background upload cancelled.');
784 return;
785 }
786
787 const file = formData.get('avatar');
788 if (!(file instanceof File)) {
789 console.error('Invalid file type for chat background upload');
790 return;
791 }
792
793 const imageDataUri = await getBase64Async(file);
794 const base64Data = imageDataUri.split(',')[1];
795 const extension = getFileExtension(file);
796 const characterName = selected_group
797 ? groups.find(g => g.id === selected_group)?.id?.toString()
798 : characters[this_chid]?.name;
799 const filename = `${characterName}_${humanizedDateTime()}`;
800 const imagePath = await saveBase64AsFile(base64Data, characterName, filename, extension);
801
802 const list = chat_metadata[LIST_METADATA_KEY] || [];
803 list.push(imagePath);
804 chat_metadata[LIST_METADATA_KEY] = list;
805 await saveMetadata();
806 renderChatBackgrounds();
807 highlightNewBackground(imagePath);
808 highlightLockedBackground();
809 highlightSelectedBackground();
810 } catch (error) {
811 console.error('Error uploading chat background:', error);
812 }
813}
814
815/**
702 * @param {string} bg816 * @param {string} bg
703 */817 */
704function highlightNewBackground(bg) {818function highlightNewBackground(bg) {
@@ -746,6 +860,14 @@ function onBackgroundFilterInput() {
746860
747const debouncedOnBackgroundFilterInput = debounce(onBackgroundFilterInput, debounce_timeout.standard);861const debouncedOnBackgroundFilterInput = debounce(onBackgroundFilterInput, debounce_timeout.standard);
748862
863/**
864 * Gets the active background tab source.
865 * @returns {BG_SOURCES} Active background tab source
866 */
867export function getActiveBackgroundTab() {
868 return $('#bg_tabs').tabs('option', 'active');
869}
870
749export function initBackgrounds() {871export function initBackgrounds() {
750 eventSource.on(event_types.CHAT_CHANGED, onChatChanged);872 eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
751 eventSource.on(event_types.FORCE_SET_BACKGROUND, forceSetBackground);873 eventSource.on(event_types.FORCE_SET_BACKGROUND, forceSetBackground);
@@ -797,7 +919,7 @@ export function initBackgrounds() {
797 applyThumbnailColumns(background_settings.thumbnailColumns + 1);919 applyThumbnailColumns(background_settings.thumbnailColumns + 1);
798 });920 });
799 $('#auto_background').on('click', autoBackgroundCommand);921 $('#auto_background').on('click', autoBackgroundCommand);
800 $('#add_bg_button').on('change', onBackgroundUploadSelected);922 $('#add_bg_button').on('change', (e) => onBackgroundUploadSelected(e.originalEvent));
801 $('#bg-filter').on('input', () => debouncedOnBackgroundFilterInput());923 $('#bg-filter').on('input', () => debouncedOnBackgroundFilterInput());
802 SlashCommandParser.addCommandObject(SlashCommand.fromProps({924 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
803 name: 'lockbg',925 name: 'lockbg',
@@ -839,9 +961,13 @@ export function initBackgrounds() {
839 await onChatChanged();961 await onChatChanged();
840 });962 });
841963
964 Object.values(BG_TABS).forEach(tabId => {
842 setupScrollToTop({965 setupScrollToTop({
843 scrollContainerId: 'bg-scrollable-content',966 scrollContainerId: tabId,
844 buttonId: 'bg-scroll-top',967 buttonId: 'bg-scroll-top',
845 drawerId: 'Backgrounds',968 drawerId: 'Backgrounds',
846 });969 });
970 });
971
972 $('#bg_tabs').tabs();
847}973}
public/scripts/keyboard.js+1 -0
@@ -19,6 +19,7 @@ const interactableSelectors = [
19 '.stscript_btn', // STscript buttons in the chat bar19 '.stscript_btn', // STscript buttons in the chat bar
20 '.select2_choice_clickable+span.select2-container .select2-selection__choice__display', // select2 control elements if they are meant to be clickable20 '.select2_choice_clickable+span.select2-container .select2-selection__choice__display', // select2 control elements if they are meant to be clickable
21 '.avatar_load_preview', // Char display avatar selection21 '.avatar_load_preview', // Char display avatar selection
22 '.bg_tabs_list .bg_tab_button', // Background tabs
22];23];
2324
24if (CSS.supports('selector(:has(*))')) {25if (CSS.supports('selector(:has(*))')) {
public/scripts/utils.js+12 -0
@@ -2775,6 +2775,17 @@ export function setupScrollToTop({ scrollContainerId, buttonId, drawerId, visibi
2775 };2775 };
2776 btn.addEventListener('click', onActivate);2776 btn.addEventListener('click', onActivate);
27772777
2778 let frameHandle = null;
2779 const resizeObserver = new ResizeObserver(() => {
2780 if (frameHandle !== null) {
2781 cancelAnimationFrame(frameHandle);
2782 }
2783 frameHandle = requestAnimationFrame(() => {
2784 updateButtonVisibilityThrottled();
2785 });
2786 });
2787 resizeObserver.observe(drawer);
2788
2778 // Initial state check2789 // Initial state check
2779 updateButtonVisibility();2790 updateButtonVisibility();
27802791
@@ -2782,6 +2793,7 @@ export function setupScrollToTop({ scrollContainerId, buttonId, drawerId, visibi
2782 return () => {2793 return () => {
2783 scrollContainer.removeEventListener('scroll', onScroll);2794 scrollContainer.removeEventListener('scroll', onScroll);
2784 btn.removeEventListener('click', onActivate);2795 btn.removeEventListener('click', onActivate);
2796 resizeObserver.disconnect();
2785 };2797 };
2786}2798}
27872799