Update BG header layout (#4519) * init * cleanup * logic changes and some styling * set z index to a reasonable value * remove pointless animation * cleanup * restore animation * checkmark icon on selected background * drop shadow * tweak size slightly * Apply suggestion from @Cohee1207 condense Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com> * more of the above * make lock indicator use a class like the selection indicator * make backgroundHighlight run on page load * cleanup * html restructure and display: contents. only issue left is slightly wonky desktop buttons order * yellow lock icon for consistancy * Update layout * Restore fitting logic * Styles clean-up * Remove duplicate class * Restore button titles * Fix return types of slash commands * Update locked background on select if lock status is on * Force header to 100% width * Clean-up styles * Fix locked highlight on custom backgrounds * Revert global lock button --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -1,6 +1,5 @@ | |||
| 1 | /* Main Page Backgrounds */ | 1 | /* Main Page Backgrounds */ |
| 2 | #bg1, | 2 | #bg1 { |
| 3 | #bg_custom { | ||
| 4 | background-repeat: no-repeat; | 3 | background-repeat: no-repeat; |
| 5 | background-attachment: fixed; | 4 | background-attachment: fixed; |
| 6 | background-size: cover; | 5 | background-size: cover; |
| @@ -8,70 +7,46 @@ | |||
| 8 | width: 100%; | 7 | width: 100%; |
| 9 | height: 100%; | 8 | height: 100%; |
| 10 | transition: background-image var(--animation-duration-3x) ease-in-out; | 9 | transition: background-image var(--animation-duration-3x) ease-in-out; |
| 10 | z-index: -1; | ||
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | /* Fitting options */ | 13 | /* Fitting options */ |
| 14 | #background_fitting { | 14 | #background_fitting { |
| 15 | max-width: 6em; | 15 | max-width: 8em; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | /* Fill/Cover - scales to fill width while maintaining aspect ratio */ | 18 | /* Fill/Cover - scales to fill width while maintaining aspect ratio */ |
| 19 | #bg1.cover, | 19 | #bg1.cover { |
| 20 | #bg_custom.cover { | ||
| 21 | background-size: cover; | 20 | background-size: cover; |
| 22 | background-position: center; | 21 | background-position: center; |
| 23 | } | 22 | } |
| 24 | 23 | ||
| 25 | /* Fit/Contain - shows entire image maintaining aspect ratio */ | 24 | /* Fit/Contain - shows entire image maintaining aspect ratio */ |
| 26 | #bg1.contain, | 25 | #bg1.contain { |
| 27 | #bg_custom.contain { | ||
| 28 | background-size: contain; | 26 | background-size: contain; |
| 29 | background-position: center; | 27 | background-position: center; |
| 30 | background-repeat: no-repeat; | 28 | background-repeat: no-repeat; |
| 31 | } | 29 | } |
| 32 | 30 | ||
| 33 | /* Stretch - stretches to fill entire space */ | 31 | /* Stretch - stretches to fill entire space */ |
| 34 | #bg1.stretch, | 32 | #bg1.stretch { |
| 35 | #bg_custom.stretch { | ||
| 36 | background-size: 100% 100%; | 33 | background-size: 100% 100%; |
| 37 | } | 34 | } |
| 38 | 35 | ||
| 39 | /* Center - centers without scaling */ | 36 | /* Center - centers without scaling */ |
| 40 | #bg1.center, | 37 | #bg1.center { |
| 41 | #bg_custom.center { | ||
| 42 | background-size: auto; | 38 | background-size: auto; |
| 43 | background-position: center; | 39 | background-position: center; |
| 44 | background-repeat: no-repeat; | 40 | background-repeat: no-repeat; |
| 45 | } | 41 | } |
| 46 | 42 | ||
| 47 | body.reduced-motion #bg1, | ||
| 48 | body.reduced-motion #bg_custom { | ||
| 49 | transition: none; | ||
| 50 | } | ||
| 51 | |||
| 52 | #bg1 { | ||
| 53 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='); | ||
| 54 | z-index: -3; | ||
| 55 | } | ||
| 56 | |||
| 57 | #bg_custom { | ||
| 58 | background-image: none; | ||
| 59 | z-index: -2; | ||
| 60 | } | ||
| 61 | |||
| 62 | .bg_example.flex-container.locked:not(:focus-visible) { | ||
| 63 | outline-color: var(--golden); | ||
| 64 | } | ||
| 65 | |||
| 66 | /* This is the main flex container for the entire drawer */ | 43 | /* This is the main flex container for the entire drawer */ |
| 67 | #Backgrounds.drawer-content.openDrawer.bg-drawer-layout { | 44 | .drawer-content.openDrawer.bg-drawer-layout { |
| 68 | display: flex; | 45 | display: flex; |
| 46 | } | ||
| 47 | |||
| 48 | .bg-drawer-layout { | ||
| 69 | flex-direction: column; | 49 | flex-direction: column; |
| 70 | height: auto; | ||
| 71 | height: calc-size(auto, size); | ||
| 72 | overflow: hidden; | ||
| 73 | width: var(--sheldWidth); | ||
| 74 | max-width: var(--sheldWidth); | ||
| 75 | padding: 0; | 50 | padding: 0; |
| 76 | } | 51 | } |
| 77 | 52 | ||
| @@ -80,12 +55,14 @@ body.reduced-motion #bg_custom { | |||
| 80 | padding: 5px; | 55 | padding: 5px; |
| 81 | background-color: var(--SmartThemeBlurTintColor); | 56 | background-color: var(--SmartThemeBlurTintColor); |
| 82 | border-bottom: 1px solid var(--SmartThemeBorderColor); | 57 | border-bottom: 1px solid var(--SmartThemeBorderColor); |
| 58 | width: 100%; | ||
| 83 | } | 59 | } |
| 84 | 60 | ||
| 85 | #bg-header-fixed>.flex-container { | 61 | .bg-header-row-1, |
| 62 | .bg-header-row-2 { | ||
| 86 | display: flex; | 63 | display: flex; |
| 87 | align-items: center; | ||
| 88 | gap: 5px; | 64 | gap: 5px; |
| 65 | width: 100%; | ||
| 89 | } | 66 | } |
| 90 | 67 | ||
| 91 | /* Control buttons in header */ | 68 | /* Control buttons in header */ |
| @@ -150,6 +127,51 @@ body.reduced-motion #bg_custom { | |||
| 150 | 127 | ||
| 151 | .bg_example:focus-visible { | 128 | .bg_example:focus-visible { |
| 152 | outline-offset: inherit; | 129 | outline-offset: inherit; |
| 130 | outline-color: var(--interactable-outline-color); | ||
| 131 | } | ||
| 132 | |||
| 133 | .bg_example.locked-background { | ||
| 134 | outline: 2px solid var(--golden); | ||
| 135 | outline-offset: 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | .bg_example.locked-background::after { | ||
| 139 | content: '\f023'; | ||
| 140 | font-family: 'Font Awesome 6 Free'; | ||
| 141 | font-weight: 900; | ||
| 142 | |||
| 143 | position: absolute; | ||
| 144 | bottom: 5px; | ||
| 145 | right: 5px; | ||
| 146 | z-index: 4; | ||
| 147 | color: var(--golden); | ||
| 148 | filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8)); | ||
| 149 | font-size: calc(var(--mainFontSize) * 0.8); | ||
| 150 | pointer-events: none; | ||
| 151 | } | ||
| 152 | |||
| 153 | .bg_example:not(.locked-background) .jg-unlock, | ||
| 154 | .bg_example.locked-background .jg-lock { | ||
| 155 | display: none; | ||
| 156 | } | ||
| 157 | |||
| 158 | .bg_example.selected-background { | ||
| 159 | outline: 2px solid white; | ||
| 160 | outline-offset: 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | .bg_example.selected-background::before { | ||
| 164 | content: '\f00c'; | ||
| 165 | font-family: 'Font Awesome 6 Free'; | ||
| 166 | font-weight: 900; | ||
| 167 | position: absolute; | ||
| 168 | top: 5px; | ||
| 169 | left: 5px; | ||
| 170 | z-index: 4; | ||
| 171 | color: var(--white100); | ||
| 172 | filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.8)); | ||
| 173 | font-size: calc(var(--mainFontSize) * 0.9); | ||
| 174 | pointer-events: none; | ||
| 153 | } | 175 | } |
| 154 | 176 | ||
| 155 | .bg_example .jg-menu { | 177 | .bg_example .jg-menu { |
| @@ -197,18 +219,6 @@ body.reduced-motion #bg_custom { | |||
| 197 | background-color: rgba(255, 255, 255, 0.2); | 219 | background-color: rgba(255, 255, 255, 0.2); |
| 198 | } | 220 | } |
| 199 | 221 | ||
| 200 | .bg_example .jg-unlock { | ||
| 201 | display: none; | ||
| 202 | } | ||
| 203 | |||
| 204 | .bg_example.locked .jg-lock { | ||
| 205 | display: none; | ||
| 206 | } | ||
| 207 | |||
| 208 | .bg_example.locked .jg-unlock { | ||
| 209 | display: flex; | ||
| 210 | } | ||
| 211 | |||
| 212 | .thumbnail-clipper { | 222 | .thumbnail-clipper { |
| 213 | position: absolute; | 223 | position: absolute; |
| 214 | top: -2px; | 224 | top: -2px; |
| @@ -88,48 +88,8 @@ | |||
| 88 | height: 30px; | 88 | height: 30px; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | #bg-header-controls { | 91 | #background_fitting { |
| 92 | flex-wrap: wrap; | 92 | max-width: 6em; |
| 93 | row-gap: 10px; | ||
| 94 | } | ||
| 95 | |||
| 96 | #bg-header-fixed>.flex-container { | ||
| 97 | flex-wrap: wrap; | ||
| 98 | row-gap: 0px; | ||
| 99 | } | ||
| 100 | |||
| 101 | #Backgrounds:not(.selection-mode-active) #bg-header-fixed>.flex-container::after { | ||
| 102 | content: ''; | ||
| 103 | order: 1; | ||
| 104 | flex-basis: 100%; | ||
| 105 | height: 0; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* --- Row 1 Item --- */ | ||
| 109 | #bg-header-fixed #bg-header-title { | ||
| 110 | order: 1; | ||
| 111 | flex-grow: 1; | ||
| 112 | } | ||
| 113 | |||
| 114 | #bg-header-fixed #background_fitting, | ||
| 115 | #bg-header-fixed #auto_background { | ||
| 116 | order: 1; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* --- Row 2 Item --- */ | ||
| 120 | #bg-header-fixed #bg-filter { | ||
| 121 | order: 2; | ||
| 122 | flex-grow: 1; | ||
| 123 | min-width: 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | /* --- Row 3 Item --- */ | ||
| 127 | #bg-header-fixed #add_background_button_top { | ||
| 128 | order: 3; | ||
| 129 | width: 100%; | ||
| 130 | text-align: center; | ||
| 131 | padding-top: 0.5em; | ||
| 132 | padding-bottom: 0.5em; | ||
| 133 | } | 93 | } |
| 134 | 94 | ||
| 135 | #Backgrounds.drawer-content.openDrawer.bg-drawer-layout { | 95 | #Backgrounds.drawer-content.openDrawer.bg-drawer-layout { |
| @@ -49,7 +49,6 @@ | |||
| 49 | 49 | ||
| 50 | <body class="no-blur"> | 50 | <body class="no-blur"> |
| 51 | <div id="preloader"></div> | 51 | <div id="preloader"></div> |
| 52 | <div id="bg_custom"></div> | ||
| 53 | <div id="bg1"></div> | 52 | <div id="bg1"></div> |
| 54 | <div id="character_context_menu" class="hidden"> | 53 | <div id="character_context_menu" class="hidden"> |
| 55 | <ul> | 54 | <ul> |
| @@ -5297,9 +5296,12 @@ | |||
| 5297 | </div> | 5296 | </div> |
| 5298 | <div id="Backgrounds" class="drawer-content closedDrawer bg-drawer-layout"> | 5297 | <div id="Backgrounds" class="drawer-content closedDrawer bg-drawer-layout"> |
| 5299 | <div id="bg-header-fixed"> | 5298 | <div id="bg-header-fixed"> |
| 5300 | <div class="flex-container alignItemsBaseline wide100p"> | 5299 | <div class="bg-header-row-1"> |
| 5301 | <h3 id="bg-header-title" class="margin0" data-i18n="Backgrounds">Backgrounds</h3> | 5300 | <label for="add_bg_button" id="add_background_button_top" class="menu_button menu_button_icon" data-i18n="[title]Add a new background" title="Add a new background"> |
| 5302 | <input id="bg-filter" class="text_pole flex1" type="search" data-i18n="[placeholder]Search" placeholder="Search" /> | 5301 | <i class="fa-solid fa-plus"></i> |
| 5302 | <span data-i18n="Add Background">Add Background</span> | ||
| 5303 | </label> | ||
| 5304 | <span class="expander"></span> | ||
| 5303 | <select id="background_fitting" class="text_pole" data-i18n="[title]Background Fitting" title="Background Fitting"> | 5305 | <select id="background_fitting" class="text_pole" data-i18n="[title]Background Fitting" title="Background Fitting"> |
| 5304 | <option value="classic" data-i18n="Classic">Classic</option> | 5306 | <option value="classic" data-i18n="Classic">Classic</option> |
| 5305 | <option value="cover" data-i18n="Cover">Cover</option> | 5307 | <option value="cover" data-i18n="Cover">Cover</option> |
| @@ -5311,10 +5313,9 @@ | |||
| 5311 | <i class="fa-solid fa-wand-magic"></i> | 5313 | <i class="fa-solid fa-wand-magic"></i> |
| 5312 | <span data-i18n="Auto-select">Auto-select</span> | 5314 | <span data-i18n="Auto-select">Auto-select</span> |
| 5313 | </div> | 5315 | </div> |
| 5314 | <label for="add_bg_button" id="add_background_button_top" class="menu_button menu_button_icon interactable" data-i18n="[title]Add a new background" title="Add a new background"> | 5316 | </div> |
| 5315 | <i class="fa-solid fa-plus"></i> | 5317 | <div class="bg-header-row-2"> |
| 5316 | <span data-i18n="Add Background">Add Background</span> | 5318 | <input id="bg-filter" class="text_pole" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." /> |
| 5317 | </label> | ||
| 5318 | </div> | 5319 | </div> |
| 5319 | </div> | 5320 | </div> |
| 5320 | <div id="bg-scrollable-content"> | 5321 | <div id="bg-scrollable-content"> |
| @@ -6284,10 +6285,9 @@ | |||
| 6284 | <i class="fa-solid fa-ellipsis-vertical"></i> | 6285 | <i class="fa-solid fa-ellipsis-vertical"></i> |
| 6285 | </div> | 6286 | </div> |
| 6286 | <div class="jg-menu"> | 6287 | <div class="jg-menu"> |
| 6287 | <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> | ||
| 6288 | <!-- temporarily moved lock icon here (will be moved to header) --> | ||
| 6289 | <div data-action="lock" class="jg-button jg-lock fa-solid fa-lock fa-fw pointer" data-i18n="[title]Lock" title="Lock"></div> | 6288 | <div data-action="lock" class="jg-button jg-lock fa-solid fa-lock fa-fw pointer" data-i18n="[title]Lock" title="Lock"></div> |
| 6290 | <div data-action="unlock" class="jg-button jg-unlock fa-solid fa-lock-open fa-fw pointer" data-i18n="[title]Unlock" title="Unlock"></div> | 6289 | <div data-action="unlock" class="jg-button jg-unlock fa-solid fa-lock-open fa-fw pointer" data-i18n="[title]Unlock" title="Unlock"></div> |
| 6290 | <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> | ||
| 6291 | <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> | 6291 | <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> |
| 6292 | <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> | 6292 | <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> |
| 6293 | </div> | 6293 | </div> |
| @@ -123,6 +123,7 @@ export function loadBackgroundSettings(settings) { | |||
| 123 | setFittingClass(backgroundSettings.fitting); | 123 | setFittingClass(backgroundSettings.fitting); |
| 124 | $('#background_fitting').val(backgroundSettings.fitting); | 124 | $('#background_fitting').val(backgroundSettings.fitting); |
| 125 | $('#background_thumbnails_animation').prop('checked', background_settings.animation); | 125 | $('#background_thumbnails_animation').prop('checked', background_settings.animation); |
| 126 | highlightSelectedBackground(); | ||
| 126 | } | 127 | } |
| 127 | 128 | ||
| 128 | /** | 129 | /** |
| @@ -131,7 +132,7 @@ export function loadBackgroundSettings(settings) { | |||
| 131 | */ | 132 | */ |
| 132 | async function forceSetBackground(backgroundInfo) { | 133 | async function forceSetBackground(backgroundInfo) { |
| 133 | saveBackgroundMetadata(backgroundInfo.url); | 134 | saveBackgroundMetadata(backgroundInfo.url); |
| 134 | setCustomBackground(); | 135 | $('#bg1').css('background-image', backgroundInfo.url); |
| 135 | 136 | ||
| 136 | const list = chat_metadata[LIST_METADATA_KEY] || []; | 137 | const list = chat_metadata[LIST_METADATA_KEY] || []; |
| 137 | const bg = backgroundInfo.path; | 138 | const bg = backgroundInfo.path; |
| @@ -144,15 +145,13 @@ async function forceSetBackground(backgroundInfo) { | |||
| 144 | } | 145 | } |
| 145 | 146 | ||
| 146 | async function onChatChanged() { | 147 | async function onChatChanged() { |
| 147 | if (hasCustomBackground()) { | 148 | const lockedUrl = chat_metadata[BG_METADATA_KEY]; |
| 148 | setCustomBackground(); | 149 | |
| 149 | } | 150 | $('#bg1').css('background-image', lockedUrl || background_settings.url); |
| 150 | else { | ||
| 151 | unsetCustomBackground(); | ||
| 152 | } | ||
| 153 | 151 | ||
| 154 | renderChatBackgrounds(); | 152 | renderChatBackgrounds(); |
| 155 | highlightLockedBackground(); | 153 | highlightLockedBackground(); |
| 154 | highlightSelectedBackground(); | ||
| 156 | } | 155 | } |
| 157 | 156 | ||
| 158 | function getBackgroundPath(fileUrl) { | 157 | function getBackgroundPath(fileUrl) { |
| @@ -160,59 +159,55 @@ function getBackgroundPath(fileUrl) { | |||
| 160 | } | 159 | } |
| 161 | 160 | ||
| 162 | function highlightLockedBackground() { | 161 | function highlightLockedBackground() { |
| 163 | $('.bg_example').removeClass('locked'); | 162 | $('.bg_example.locked-background').removeClass('locked-background'); |
| 164 | 163 | ||
| 165 | const lockedBackground = chat_metadata[BG_METADATA_KEY]; | 164 | const lockedBackgroundUrl = chat_metadata[BG_METADATA_KEY]; |
| 166 | |||
| 167 | if (!lockedBackground) { | ||
| 168 | return; | ||
| 169 | } | ||
| 170 | 165 | ||
| 171 | $('.bg_example').each(function () { | 166 | if (lockedBackgroundUrl) { |
| 172 | const url = $(this).data('url'); | 167 | $('.bg_example').filter(function () { |
| 173 | if (url === lockedBackground) { | 168 | return $(this).data('url') === lockedBackgroundUrl; |
| 174 | $(this).addClass('locked'); | 169 | }).addClass('locked-background'); |
| 175 | } | 170 | } |
| 176 | }); | ||
| 177 | } | 171 | } |
| 178 | 172 | ||
| 179 | /** | 173 | /** |
| 180 | * Locks the background for the current chat | 174 | * Locks the background for the current chat |
| 181 | * @param {Event} e Click event | 175 | * @param {Event|null} event |
| 182 | * @returns {string} Empty string | ||
| 183 | */ | 176 | */ |
| 184 | function onLockBackgroundClick(e) { | 177 | function onLockBackgroundClick(event = null) { |
| 185 | e?.stopPropagation(); | 178 | if (!getCurrentChatId()) { |
| 186 | 179 | toastr.warning(t`Select a chat to lock the background for it`); | |
| 187 | const chatName = getCurrentChatId(); | 180 | return; |
| 188 | |||
| 189 | if (!chatName) { | ||
| 190 | toastr.warning('Select a chat to lock the background for it'); | ||
| 191 | return ''; | ||
| 192 | } | 181 | } |
| 193 | 182 | ||
| 194 | const relativeBgImage = getUrlParameter(this) ?? background_settings.url; | 183 | // Take the global background's URL and save it to the chat's metadata. |
| 184 | const urlToLock = event ? $(event.target).closest('.bg_example').data('url') : background_settings.url; | ||
| 185 | saveBackgroundMetadata(urlToLock); | ||
| 186 | $('#bg1').css('background-image', urlToLock); | ||
| 195 | 187 | ||
| 196 | saveBackgroundMetadata(relativeBgImage); | 188 | // Update UI states to reflect the new lock. |
| 197 | setCustomBackground(); | ||
| 198 | highlightLockedBackground(); | 189 | highlightLockedBackground(); |
| 199 | return ''; | 190 | toastr.success(t`Background locked for this chat.`); |
| 200 | } | 191 | } |
| 201 | 192 | ||
| 202 | /** | 193 | /** |
| 203 | * Locks the background for the current chat | 194 | * Unlocks the background for the current chat |
| 204 | * @param {Event} e Click event | 195 | * @param {Event|null} _event |
| 205 | * @returns {string} Empty string | ||
| 206 | */ | 196 | */ |
| 207 | function onUnlockBackgroundClick(e) { | 197 | function onUnlockBackgroundClick(_event = null) { |
| 208 | e?.stopPropagation(); | 198 | // Delete the lock from the chat's metadata. |
| 209 | removeBackgroundMetadata(); | 199 | removeBackgroundMetadata(); |
| 210 | unsetCustomBackground(); | 200 | |
| 201 | // Revert the view to the current global background. | ||
| 202 | $('#bg1').css('background-image', background_settings.url); | ||
| 203 | |||
| 204 | // Update UI states to reflect the removal of the lock. | ||
| 211 | highlightLockedBackground(); | 205 | highlightLockedBackground(); |
| 212 | return ''; | 206 | highlightSelectedBackground(); |
| 207 | toastr.success(t`Background unlocked for this chat.`); | ||
| 213 | } | 208 | } |
| 214 | 209 | ||
| 215 | function hasCustomBackground() { | 210 | function isChatBackgroundLocked() { |
| 216 | return chat_metadata[BG_METADATA_KEY]; | 211 | return chat_metadata[BG_METADATA_KEY]; |
| 217 | } | 212 | } |
| 218 | 213 | ||
| @@ -226,54 +221,22 @@ function removeBackgroundMetadata() { | |||
| 226 | saveMetadataDebounced(); | 221 | saveMetadataDebounced(); |
| 227 | } | 222 | } |
| 228 | 223 | ||
| 229 | function setCustomBackground() { | ||
| 230 | const file = chat_metadata[BG_METADATA_KEY]; | ||
| 231 | |||
| 232 | // bg already set | ||
| 233 | if (document.getElementById('bg_custom').style.backgroundImage == file) { | ||
| 234 | return; | ||
| 235 | } | ||
| 236 | |||
| 237 | $('#bg_custom').css('background-image', file); | ||
| 238 | } | ||
| 239 | |||
| 240 | function unsetCustomBackground() { | ||
| 241 | $('#bg_custom').css('background-image', 'none'); | ||
| 242 | } | ||
| 243 | |||
| 244 | function onSelectBackgroundClick() { | 224 | function onSelectBackgroundClick() { |
| 245 | const isCustom = $(this).attr('custom') === 'true'; | 225 | const bgFile = $(this).attr('bgfile'); |
| 246 | const relativeBgImage = getUrlParameter(this); | 226 | const backgroundCssUrl = getUrlParameter(this); |
| 247 | |||
| 248 | // if clicked on upload button | ||
| 249 | if (!relativeBgImage) { | ||
| 250 | return; | ||
| 251 | } | ||
| 252 | 227 | ||
| 253 | // Automatically lock the background if it's custom or other background is locked | 228 | if (isChatBackgroundLocked()) { |
| 254 | if (hasCustomBackground() || isCustom) { | 229 | // If a background is locked, update the locked background directly |
| 255 | saveBackgroundMetadata(relativeBgImage); | 230 | saveBackgroundMetadata(backgroundCssUrl); |
| 256 | setCustomBackground(); | 231 | $('#bg1').css('background-image', backgroundCssUrl); |
| 257 | highlightLockedBackground(); | 232 | highlightLockedBackground(); |
| 233 | } else { | ||
| 234 | // Otherwise, update the global background setting | ||
| 235 | setBackground(bgFile, backgroundCssUrl); | ||
| 258 | } | 236 | } |
| 259 | highlightLockedBackground(); | ||
| 260 | |||
| 261 | const customBg = window.getComputedStyle(document.getElementById('bg_custom')).backgroundImage; | ||
| 262 | 237 | ||
| 263 | // Custom background is set. Do not override the layer below | 238 | // Update UI highlights to reflect the changes. |
| 264 | if (customBg !== 'none') { | 239 | highlightSelectedBackground(); |
| 265 | return; | ||
| 266 | } | ||
| 267 | |||
| 268 | const bgFile = $(this).attr('bgfile'); | ||
| 269 | const backgroundUrl = getBackgroundPath(bgFile); | ||
| 270 | |||
| 271 | // Fetching to browser memory to reduce flicker | ||
| 272 | fetch(backgroundUrl).then(() => { | ||
| 273 | setBackground(bgFile, relativeBgImage); | ||
| 274 | }).catch(() => { | ||
| 275 | console.log('Background could not be set: ' + backgroundUrl); | ||
| 276 | }); | ||
| 277 | } | 240 | } |
| 278 | 241 | ||
| 279 | async function onCopyToSystemBackgroundClick(e) { | 242 | async function onCopyToSystemBackgroundClick(e) { |
| @@ -448,7 +411,6 @@ async function onDeleteBackgroundClick(e) { | |||
| 448 | 411 | ||
| 449 | if (url === chat_metadata[BG_METADATA_KEY]) { | 412 | if (url === chat_metadata[BG_METADATA_KEY]) { |
| 450 | removeBackgroundMetadata(); | 413 | removeBackgroundMetadata(); |
| 451 | unsetCustomBackground(); | ||
| 452 | highlightLockedBackground(); | 414 | highlightLockedBackground(); |
| 453 | } | 415 | } |
| 454 | 416 | ||
| @@ -544,7 +506,9 @@ export async function getBackgrounds() { | |||
| 544 | if (response.ok) { | 506 | if (response.ok) { |
| 545 | const { images, config } = await response.json(); | 507 | const { images, config } = await response.json(); |
| 546 | Object.assign(THUMBNAIL_CONFIG, config); | 508 | Object.assign(THUMBNAIL_CONFIG, config); |
| 509 | |||
| 547 | renderSystemBackgrounds(images); | 510 | renderSystemBackgrounds(images); |
| 511 | highlightSelectedBackground(); | ||
| 548 | } | 512 | } |
| 549 | } | 513 | } |
| 550 | 514 | ||
| @@ -620,7 +584,10 @@ async function resolveImageUrl(bg, isCustom) { | |||
| 620 | } | 584 | } |
| 621 | 585 | ||
| 622 | async function setBackground(bg, url) { | 586 | async function setBackground(bg, url) { |
| 587 | // Only change the visual background if one is not locked for the current chat. | ||
| 588 | if (!isChatBackgroundLocked()) { | ||
| 623 | $('#bg1').css('background-image', url); | 589 | $('#bg1').css('background-image', url); |
| 590 | } | ||
| 624 | background_settings.name = bg; | 591 | background_settings.name = bg; |
| 625 | background_settings.url = url; | 592 | background_settings.url = url; |
| 626 | saveSettingsDebounced(); | 593 | saveSettingsDebounced(); |
| @@ -748,13 +715,27 @@ function highlightNewBackground(bg) { | |||
| 748 | * @param {string} fitting Fitting type | 715 | * @param {string} fitting Fitting type |
| 749 | */ | 716 | */ |
| 750 | function setFittingClass(fitting) { | 717 | function setFittingClass(fitting) { |
| 751 | const backgrounds = $('#bg1, #bg_custom'); | 718 | const backgrounds = $('#bg1'); |
| 752 | for (const option of ['cover', 'contain', 'stretch', 'center']) { | 719 | for (const option of ['cover', 'contain', 'stretch', 'center']) { |
| 753 | backgrounds.toggleClass(option, option === fitting); | 720 | backgrounds.toggleClass(option, option === fitting); |
| 754 | } | 721 | } |
| 755 | background_settings.fitting = fitting; | 722 | background_settings.fitting = fitting; |
| 756 | } | 723 | } |
| 757 | 724 | ||
| 725 | function highlightSelectedBackground() { | ||
| 726 | $('.bg_example.selected-background').removeClass('selected-background'); | ||
| 727 | |||
| 728 | // The "selected" highlight should always reflect the global background setting. | ||
| 729 | const activeUrl = background_settings.url; | ||
| 730 | |||
| 731 | if (activeUrl) { | ||
| 732 | // Find the thumbnail whose data-url attribute matches the active URL | ||
| 733 | $('.bg_example').filter(function () { | ||
| 734 | return $(this).data('url') === activeUrl; | ||
| 735 | }).addClass('selected-background'); | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 758 | function onBackgroundFilterInput() { | 739 | function onBackgroundFilterInput() { |
| 759 | const filterValue = String($('#bg-filter').val()).toLowerCase(); | 740 | const filterValue = String($('#bg-filter').val()).toLowerCase(); |
| 760 | $('#bg_menu_content > .bg_example, #bg_custom_content > .bg_example').each(function () { | 741 | $('#bg_menu_content > .bg_example, #bg_custom_content > .bg_example').each(function () { |
| @@ -822,13 +803,19 @@ export function initBackgrounds() { | |||
| 822 | $('#bg-filter').on('input', () => debouncedOnBackgroundFilterInput()); | 803 | $('#bg-filter').on('input', () => debouncedOnBackgroundFilterInput()); |
| 823 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 804 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 824 | name: 'lockbg', | 805 | name: 'lockbg', |
| 825 | callback: () => onLockBackgroundClick(new CustomEvent('click')), | 806 | callback: () => { |
| 807 | onLockBackgroundClick(); | ||
| 808 | return ''; | ||
| 809 | }, | ||
| 826 | aliases: ['bglock'], | 810 | aliases: ['bglock'], |
| 827 | helpString: 'Locks a background for the currently selected chat', | 811 | helpString: 'Locks a background for the currently selected chat', |
| 828 | })); | 812 | })); |
| 829 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 813 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 830 | name: 'unlockbg', | 814 | name: 'unlockbg', |
| 831 | callback: () => onUnlockBackgroundClick(new CustomEvent('click')), | 815 | callback: () => { |
| 816 | onUnlockBackgroundClick(); | ||
| 817 | return ''; | ||
| 818 | }, | ||
| 832 | aliases: ['bgunlock'], | 819 | aliases: ['bgunlock'], |
| 833 | helpString: 'Unlocks a background for the currently selected chat', | 820 | helpString: 'Unlocks a background for the currently selected chat', |
| 834 | })); | 821 | })); |