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
Signed| @@ -84,14 +84,6 @@ | |||
| 84 | gap: 5px; | 84 | gap: 5px; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 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 | } | ||
| @@ -97,6 +97,10 @@ | |||
| 97 | max-width: 100dvw; | 97 | max-width: 100dvw; |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 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; |
| @@ -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 Backgrounds | 5424 | <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"> | 5443 | <div id="bg_chat_hint" class="wide100p textAlignCenter"> |
| 5438 | Chat Backgrounds | 5444 | <span data-i18n="bg_chat_hint_1">Chat backgrounds generated with the</span> <code><i class="fa-solid fa-paintbrush"></i> Image Generation</code> <span data-i18n="bg_chat_hint_2">extension will appear here.</span> |
| 5439 | </h3> | 5445 | </div> |
| 5440 | <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> Image Generation</code> <span data-i18n="bg_chat_hint_2">extension will appear here.</span> | ||
| 5442 | </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> |
| @@ -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": "الغاء القفل", |
| @@ -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", |
| @@ -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", |
| @@ -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", |
| @@ -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", |
| @@ -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", |
| @@ -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": "ロック解除", |
| @@ -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": "잠금 해제", |
| @@ -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", |
| @@ -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", |
| @@ -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.", |
| @@ -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": "ปลดล็อค", |
| @@ -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": "Розблокувати", |
| @@ -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", |
| @@ -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": "重命名背景", |
| @@ -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": "解鎖", |
| @@ -50,6 +50,14 @@ const toolbarSelectors = [ | |||
| 50 | '.jg-menu', | 50 | '.jg-menu', |
| 51 | ].join(', '); | 51 | ].join(', '); |
| 52 | 52 | ||
| 53 | const tabListSelectors = [ | ||
| 54 | '#bg_tabs .bg_tabs_list', | ||
| 55 | ].join(', '); | ||
| 56 | |||
| 57 | const 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>} */ |
| 54 | const a11yRules = { | 62 | const 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 | }, |
| @@ -1,12 +1,15 @@ | |||
| 1 | import { Fuse, localforage } from '../lib.js'; | 1 | import { Fuse, localforage } from '../lib.js'; |
| 2 | import { chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveSettingsDebounced } from '../script.js'; | 2 | import { characters, chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveMetadata, saveSettingsDebounced, this_chid } from '../script.js'; |
| 3 | import { openThirdPartyExtensionMenu, saveMetadataDebounced } from './extensions.js'; | 3 | import { openThirdPartyExtensionMenu, saveMetadataDebounced } from './extensions.js'; |
| 4 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 4 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 5 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 5 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 6 | import { createThumbnail, flashHighlight, getBase64Async, stringFormat, debounce, setupScrollToTop } from './utils.js'; | 6 | import { createThumbnail, flashHighlight, getBase64Async, stringFormat, debounce, setupScrollToTop, saveBase64AsFile, getFileExtension } from './utils.js'; |
| 7 | import { debounce_timeout } from './constants.js'; | 7 | import { debounce_timeout } from './constants.js'; |
| 8 | import { t } from './i18n.js'; | 8 | import { t } from './i18n.js'; |
| 9 | import { Popup } from './popup.js'; | 9 | import { Popup } from './popup.js'; |
| 10 | import { groups, selected_group } from './group-chats.js'; | ||
| 11 | import { humanizedDateTime } from './RossAscends-mods.js'; | ||
| 12 | import { deleteMediaFromServer } from './chats.js'; | ||
| 10 | 13 | ||
| 11 | const BG_METADATA_KEY = 'custom_background'; | 14 | const BG_METADATA_KEY = 'custom_background'; |
| 12 | const LIST_METADATA_KEY = 'chat_backgrounds'; | 15 | const LIST_METADATA_KEY = 'chat_backgrounds'; |
| @@ -39,6 +42,26 @@ const THUMBNAIL_CONFIG = { | |||
| 39 | }; | 42 | }; |
| 40 | 43 | ||
| 41 | /** | 44 | /** |
| 45 | * Background source types. | ||
| 46 | * @readonly | ||
| 47 | * @enum {number} | ||
| 48 | */ | ||
| 49 | const 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 | */ | ||
| 59 | const 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 backgrounds | 65 | * 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) { | |||
| 187 | 210 | ||
| 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 | } |
| 191 | 215 | ||
| 192 | /** | 216 | /** |
| @@ -219,21 +243,27 @@ function removeBackgroundMetadata() { | |||
| 219 | saveMetadataDebounced(); | 243 | saveMetadataDebounced(); |
| 220 | } | 244 | } |
| 221 | 245 | ||
| 222 | function onSelectBackgroundClick() { | 246 | /** |
| 247 | * Handles the click event for selecting a background. | ||
| 248 | * @param {JQuery.Event} e Event | ||
| 249 | */ | ||
| 250 | function 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; | ||
| 225 | 255 | ||
| 226 | if (isChatBackgroundLocked()) { | 256 | if ((isChatBackgroundLocked() || isCustom) && !bypassGlobalLock) { |
| 227 | // If a background is locked, update the locked background directly | 257 | // 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 setting | 261 | // Otherwise, update the global background setting |
| 233 | setBackground(bgFile, backgroundCssUrl); | 262 | setBackground(bgFile, backgroundCssUrl); |
| 234 | } | 263 | } |
| 235 | 264 | ||
| 236 | // Update UI highlights to reflect the changes. | 265 | // Update UI highlights to reflect the changes. |
| 266 | highlightLockedBackground(); | ||
| 237 | highlightSelectedBackground(); | 267 | highlightSelectedBackground(); |
| 238 | } | 268 | } |
| 239 | 269 | ||
| @@ -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'); |
| 380 | 427 | ||
| 381 | if (confirm) { | 428 | if (confirm) { |
| 382 | // If it's not custom, it's a built-in background. Delete it from the server | 429 | // 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 | } |
| 390 | 437 | ||
| 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) { | |||
| 409 | 456 | ||
| 410 | if (url === chat_metadata[BG_METADATA_KEY]) { | 457 | if (url === chat_metadata[BG_METADATA_KEY]) { |
| 411 | removeBackgroundMetadata(); | 458 | removeBackgroundMetadata(); |
| 412 | highlightLockedBackground(); | ||
| 413 | } | 459 | } |
| 414 | 460 | ||
| 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 | } |
| 421 | 473 | ||
| @@ -607,25 +659,43 @@ async function delBackground(bg) { | |||
| 607 | } | 659 | } |
| 608 | } | 660 | } |
| 609 | 661 | ||
| 610 | async 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 | */ | ||
| 667 | async function onBackgroundUploadSelected(e) { | ||
| 668 | const input = e.currentTarget; | ||
| 612 | 669 | ||
| 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 | } |
| 617 | 674 | ||
| 618 | const formData = new FormData(form); | 675 | for (const file of input.files) { |
| 676 | if (file.size === 0) { | ||
| 677 | continue; | ||
| 678 | } | ||
| 619 | 679 | ||
| 620 | const file = formData.get('avatar'); | 680 | const formData = new FormData(); |
| 621 | if (!(file instanceof File) || file.size === 0) { | 681 | formData.append('avatar', file); |
| 622 | form.reset(); | 682 | |
| 623 | return; | 683 | await convertFileIfVideo(formData); |
| 684 | switch (getActiveBackgroundTab()) { | ||
| 685 | case BG_SOURCES.GLOBAL: | ||
| 686 | await uploadBackground(formData); | ||
| 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 | } | ||
| 624 | } | 695 | } |
| 625 | 696 | ||
| 626 | await convertFileIfVideo(formData); | 697 | // Allow re-uploading the same file again by clearing the input value |
| 627 | await uploadBackground(formData); | 698 | input.value = ''; |
| 628 | form.reset(); | ||
| 629 | } | 699 | } |
| 630 | 700 | ||
| 631 | /** | 701 | /** |
| @@ -699,6 +769,50 @@ async function uploadBackground(formData) { | |||
| 699 | } | 769 | } |
| 700 | 770 | ||
| 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 | */ | ||
| 776 | async 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} bg | 816 | * @param {string} bg |
| 703 | */ | 817 | */ |
| 704 | function highlightNewBackground(bg) { | 818 | function highlightNewBackground(bg) { |
| @@ -746,6 +860,14 @@ function onBackgroundFilterInput() { | |||
| 746 | 860 | ||
| 747 | const debouncedOnBackgroundFilterInput = debounce(onBackgroundFilterInput, debounce_timeout.standard); | 861 | const debouncedOnBackgroundFilterInput = debounce(onBackgroundFilterInput, debounce_timeout.standard); |
| 748 | 862 | ||
| 863 | /** | ||
| 864 | * Gets the active background tab source. | ||
| 865 | * @returns {BG_SOURCES} Active background tab source | ||
| 866 | */ | ||
| 867 | export function getActiveBackgroundTab() { | ||
| 868 | return $('#bg_tabs').tabs('option', 'active'); | ||
| 869 | } | ||
| 870 | |||
| 749 | export function initBackgrounds() { | 871 | export 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 | }); |
| 841 | 963 | ||
| 842 | setupScrollToTop({ | 964 | Object.values(BG_TABS).forEach(tabId => { |
| 843 | scrollContainerId: 'bg-scrollable-content', | 965 | setupScrollToTop({ |
| 844 | buttonId: 'bg-scroll-top', | 966 | scrollContainerId: tabId, |
| 845 | drawerId: 'Backgrounds', | 967 | buttonId: 'bg-scroll-top', |
| 968 | drawerId: 'Backgrounds', | ||
| 969 | }); | ||
| 846 | }); | 970 | }); |
| 971 | |||
| 972 | $('#bg_tabs').tabs(); | ||
| 847 | } | 973 | } |
| @@ -19,6 +19,7 @@ const interactableSelectors = [ | |||
| 19 | '.stscript_btn', // STscript buttons in the chat bar | 19 | '.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 clickable | 20 | '.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 selection | 21 | '.avatar_load_preview', // Char display avatar selection |
| 22 | '.bg_tabs_list .bg_tab_button', // Background tabs | ||
| 22 | ]; | 23 | ]; |
| 23 | 24 | ||
| 24 | if (CSS.supports('selector(:has(*))')) { | 25 | if (CSS.supports('selector(:has(*))')) { |
| @@ -2775,6 +2775,17 @@ export function setupScrollToTop({ scrollContainerId, buttonId, drawerId, visibi | |||
| 2775 | }; | 2775 | }; |
| 2776 | btn.addEventListener('click', onActivate); | 2776 | btn.addEventListener('click', onActivate); |
| 2777 | 2777 | ||
| 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 check | 2789 | // Initial state check |
| 2779 | updateButtonVisibility(); | 2790 | updateButtonVisibility(); |
| 2780 | 2791 | ||
| @@ -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 | } |
| 2787 | 2799 | ||