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>

4127b688c9e54efb41eee87fe3bd108d2a8b4936

L <123923688+Vibecoder9000@users.noreply.github.com>

Signed
4 files changed, +147 -190Ignore whitespace
public/css/backgrounds.css+60 -50
@@ -1,6 +1,5 @@
11/* Main Page Backgrounds */
22#bg1, {
3-#bg_custom {
43 background-repeat: no-repeat;
54 background-attachment: fixed;
65 background-size: cover;
@@ -8,70 +7,46 @@
87 width: 100%;
98 height: 100%;
109 transition: background-image var(--animation-duration-3x) ease-in-out;
10+ z-index: -1;
1111}
1212
1313/* Fitting options */
1414#background_fitting {
1515 max-width: 6em8em;
1616}
1717
1818/* Fill/Cover - scales to fill width while maintaining aspect ratio */
1919#bg1.cover, {
20-#bg_custom.cover {
2120 background-size: cover;
2221 background-position: center;
2322}
2423
2524/* Fit/Contain - shows entire image maintaining aspect ratio */
2625#bg1.contain, {
27-#bg_custom.contain {
2826 background-size: contain;
2927 background-position: center;
3028 background-repeat: no-repeat;
3129}
3230
3331/* Stretch - stretches to fill entire space */
3432#bg1.stretch, {
35-#bg_custom.stretch {
3633 background-size: 100% 100%;
3734}
3835
3936/* Center - centers without scaling */
4037#bg1.center, {
41-#bg_custom.center {
4238 background-size: auto;
4339 background-position: center;
4440 background-repeat: no-repeat;
4541}
4642
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-
6643/* This is the main flex container for the entire drawer */
6744#Backgrounds.drawer-content.openDrawer.bg-drawer-layout {
6845 display: flex;
46+}
47+
48+.bg-drawer-layout {
6949 flex-direction: column;
70- height: auto;
71- height: calc-size(auto, size);
72- overflow: hidden;
73- width: var(--sheldWidth);
74- max-width: var(--sheldWidth);
7550 padding: 0;
7651}
7752
@@ -80,12 +55,14 @@ body.reduced-motion #bg_custom {
8055 padding: 5px;
8156 background-color: var(--SmartThemeBlurTintColor);
8257 border-bottom: 1px solid var(--SmartThemeBorderColor);
58+ width: 100%;
8359}
8460
85-#bg-header-fixed>.flex-container {
61+.bg-header-row-1,
62+.bg-header-row-2 {
8663 display: flex;
87- align-items: center;
8864 gap: 5px;
65+ width: 100%;
8966}
9067
9168/* Control buttons in header */
@@ -150,6 +127,51 @@ body.reduced-motion #bg_custom {
150127
151128.bg_example:focus-visible {
152129 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;
153175}
154176
155177.bg_example .jg-menu {
@@ -197,18 +219,6 @@ body.reduced-motion #bg_custom {
197219 background-color: rgba(255, 255, 255, 0.2);
198220}
199221
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-
212222.thumbnail-clipper {
213223 position: absolute;
214224 top: -2px;
public/css/mobile-styles.css+2 -42
@@ -88,48 +88,8 @@
8888 height: 30px;
8989 }
9090
9191 #bg-header-controlsbackground_fitting {
9292 flexmax-wrapwidth: wrap6em;
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;
13393 }
13494
13595 #Backgrounds.drawer-content.openDrawer.bg-drawer-layout {
public/index.html+10 -10
@@ -49,7 +49,6 @@
4949
5050<body class="no-blur">
5151 <div id="preloader"></div>
52- <div id="bg_custom"></div>
5352 <div id="bg1"></div>
5453 <div id="character_context_menu" class="hidden">
5554 <ul>
@@ -5297,9 +5296,12 @@
52975296 </div>
52985297 <div id="Backgrounds" class="drawer-content closedDrawer bg-drawer-layout">
52995298 <div id="bg-header-fixed">
53005299 <div class="flexbg-container alignItemsBaseline wide100pheader-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>
53035305 <select id="background_fitting" class="text_pole" data-i18n="[title]Background Fitting" title="Background Fitting">
53045306 <option value="classic" data-i18n="Classic">Classic</option>
53055307 <option value="cover" data-i18n="Cover">Cover</option>
@@ -5311,10 +5313,9 @@
53115313 <i class="fa-solid fa-wand-magic"></i>
53125314 <span data-i18n="Auto-select">Auto-select</span>
53135315 </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>
53155317 <idiv class="fabg-solid faheader-plusrow-2"></i>
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>
53185319 </div>
53195320 </div>
53205321 <div id="bg-scrollable-content">
@@ -6284,10 +6285,9 @@
62846285 <i class="fa-solid fa-ellipsis-vertical"></i>
62856286 </div>
62866287 <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) -->
62896288 <div data-action="lock" class="jg-button jg-lock fa-solid fa-lock fa-fw pointer" data-i18n="[title]Lock" title="Lock"></div>
62906289 <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>
62916291 <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>
62926292 <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>
62936293 </div>
public/scripts/backgrounds.js+75 -88
@@ -123,6 +123,7 @@ export function loadBackgroundSettings(settings) {
123123 setFittingClass(backgroundSettings.fitting);
124124 $('#background_fitting').val(backgroundSettings.fitting);
125125 $('#background_thumbnails_animation').prop('checked', background_settings.animation);
126+ highlightSelectedBackground();
126127}
127128
128129/**
@@ -131,7 +132,7 @@ export function loadBackgroundSettings(settings) {
131132 */
132133async function forceSetBackground(backgroundInfo) {
133134 saveBackgroundMetadata(backgroundInfo.url);
134- setCustomBackground();
135+ $('#bg1').css('background-image', backgroundInfo.url);
135136
136137 const list = chat_metadata[LIST_METADATA_KEY] || [];
137138 const bg = backgroundInfo.path;
@@ -144,15 +145,13 @@ async function forceSetBackground(backgroundInfo) {
144145}
145146
146147async 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- }
153151
154152 renderChatBackgrounds();
155153 highlightLockedBackground();
154+ highlightSelectedBackground();
156155}
157156
158157function getBackgroundPath(fileUrl) {
@@ -160,59 +159,55 @@ function getBackgroundPath(fileUrl) {
160159}
161160
162161function highlightLockedBackground() {
163162 $('.bg_example.locked-background').removeClass('locked-background');
164163
165164 const lockedBackgroundlockedBackgroundUrl = chat_metadata[BG_METADATA_KEY];
166165
167166 if (!lockedBackgroundlockedBackgroundUrl) {
168- return;
167+ $('.bg_example').filter(function () {
168+ return $(this).data('url') === lockedBackgroundUrl;
169+ }).addClass('locked-background');
169170 }
170-
171- $('.bg_example').each(function () {
172- const url = $(this).data('url');
173- if (url === lockedBackground) {
174- $(this).addClass('locked');
175- }
176- });
177171}
178172
179173/**
180174 * Locks the background for the current chat
181175 * @param {Event|null} e Click event
182- * @returns {string} Empty string
183176 */
184177function onLockBackgroundClick(eevent = 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 '';
192181 }
193182
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);
195187
196- saveBackgroundMetadata(relativeBgImage);
188+ // Update UI states to reflect the new lock.
197- setCustomBackground();
198189 highlightLockedBackground();
199- return '';
190+ toastr.success(t`Background locked for this chat.`);
200191}
201192
202193/**
203194 * LocksUnlocks the background for the current chat
204195 * @param {Event|null} e Click event_event
205- * @returns {string} Empty string
206196 */
207197function onUnlockBackgroundClick(e_event = null) {
208- e?.stopPropagation();
198+ // Delete the lock from the chat's metadata.
209199 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.
211205 highlightLockedBackground();
212- return '';
206+ highlightSelectedBackground();
207+ toastr.success(t`Background unlocked for this chat.`);
213208}
214209
215210function hasCustomBackgroundisChatBackgroundLocked() {
216211 return chat_metadata[BG_METADATA_KEY];
217212}
218213
@@ -226,54 +221,22 @@ function removeBackgroundMetadata() {
226221 saveMetadataDebounced();
227222}
228223
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-
244224function onSelectBackgroundClick() {
245225 const isCustombgFile = $(this).attr('custombgfile') === 'true';
246226 const relativeBgImagebackgroundCssUrl = getUrlParameter(this);
247-
248- // if clicked on upload button
249- if (!relativeBgImage) {
250- return;
251- }
252227
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
255230 saveBackgroundMetadata(relativeBgImagebackgroundCssUrl);
256- setCustomBackground();
231+ $('#bg1').css('background-image', backgroundCssUrl);
257232 highlightLockedBackground();
233+ } else {
234+ // Otherwise, update the global background setting
235+ setBackground(bgFile, backgroundCssUrl);
258236 }
259- highlightLockedBackground();
260-
261- const customBg = window.getComputedStyle(document.getElementById('bg_custom')).backgroundImage;
262-
263- // Custom background is set. Do not override the layer below
264- if (customBg !== 'none') {
265- return;
266- }
267-
268- const bgFile = $(this).attr('bgfile');
269- const backgroundUrl = getBackgroundPath(bgFile);
270237
271238 // Fetching toUpdate browserUI memoryhighlights to reducereflect flickerthe changes.
272- fetch(backgroundUrl).then(() => {
239+ highlightSelectedBackground();
273- setBackground(bgFile, relativeBgImage);
274- }).catch(() => {
275- console.log('Background could not be set: ' + backgroundUrl);
276- });
277240}
278241
279242async function onCopyToSystemBackgroundClick(e) {
@@ -448,7 +411,6 @@ async function onDeleteBackgroundClick(e) {
448411
449412 if (url === chat_metadata[BG_METADATA_KEY]) {
450413 removeBackgroundMetadata();
451- unsetCustomBackground();
452414 highlightLockedBackground();
453415 }
454416
@@ -544,7 +506,9 @@ export async function getBackgrounds() {
544506 if (response.ok) {
545507 const { images, config } = await response.json();
546508 Object.assign(THUMBNAIL_CONFIG, config);
509+
547510 renderSystemBackgrounds(images);
511+ highlightSelectedBackground();
548512 }
549513}
550514
@@ -620,7 +584,10 @@ async function resolveImageUrl(bg, isCustom) {
620584}
621585
622586async function setBackground(bg, url) {
623- $('#bg1').css('background-image', url);
587+ // Only change the visual background if one is not locked for the current chat.
588+ if (!isChatBackgroundLocked()) {
589+ $('#bg1').css('background-image', url);
590+ }
624591 background_settings.name = bg;
625592 background_settings.url = url;
626593 saveSettingsDebounced();
@@ -748,13 +715,27 @@ function highlightNewBackground(bg) {
748715 * @param {string} fitting Fitting type
749716 */
750717function setFittingClass(fitting) {
751718 const backgrounds = $('#bg1, #bg_custom');
752719 for (const option of ['cover', 'contain', 'stretch', 'center']) {
753720 backgrounds.toggleClass(option, option === fitting);
754721 }
755722 background_settings.fitting = fitting;
756723}
757724
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+
758739function onBackgroundFilterInput() {
759740 const filterValue = String($('#bg-filter').val()).toLowerCase();
760741 $('#bg_menu_content > .bg_example, #bg_custom_content > .bg_example').each(function () {
@@ -822,13 +803,19 @@ export function initBackgrounds() {
822803 $('#bg-filter').on('input', () => debouncedOnBackgroundFilterInput());
823804 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
824805 name: 'lockbg',
825806 callback: () => onLockBackgroundClick(new CustomEvent('click')),{
807+ onLockBackgroundClick();
808+ return '';
809+ },
826810 aliases: ['bglock'],
827811 helpString: 'Locks a background for the currently selected chat',
828812 }));
829813 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
830814 name: 'unlockbg',
831815 callback: () => onUnlockBackgroundClick(new CustomEvent('click')),{
816+ onUnlockBackgroundClick();
817+ return '';
818+ },
832819 aliases: ['bgunlock'],
833820 helpString: 'Unlocks a background for the currently selected chat',
834821 }));