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 @@
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}
1212
13/* Fitting options */13/* Fitting options */
14#background_fitting {14#background_fitting {
15 max-width: 6em;15 max-width: 8em;
16}16}
1717
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}
2423
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}
3230
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}
3835
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}
4642
47body.reduced-motion #bg1,
48body.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}
7752
@@ -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}
8460
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}
9067
91/* Control buttons in header */68/* Control buttons in header */
@@ -150,6 +127,51 @@ body.reduced-motion #bg_custom {
150127
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}
154176
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}
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
212.thumbnail-clipper {222.thumbnail-clipper {
213 position: absolute;223 position: absolute;
214 top: -2px;224 top: -2px;
public/css/mobile-styles.css+2 -42
@@ -88,48 +88,8 @@
88 height: 30px;88 height: 30px;
89 }89 }
9090
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 }
13494
135 #Backgrounds.drawer-content.openDrawer.bg-drawer-layout {95 #Backgrounds.drawer-content.openDrawer.bg-drawer-layout {
public/index.html+10 -10
@@ -49,7 +49,6 @@
4949
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>
public/scripts/backgrounds.js+75 -88
@@ -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}
127128
128/**129/**
@@ -131,7 +132,7 @@ export function loadBackgroundSettings(settings) {
131 */132 */
132async function forceSetBackground(backgroundInfo) {133async function forceSetBackground(backgroundInfo) {
133 saveBackgroundMetadata(backgroundInfo.url);134 saveBackgroundMetadata(backgroundInfo.url);
134 setCustomBackground();135 $('#bg1').css('background-image', backgroundInfo.url);
135136
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}
145146
146async function onChatChanged() {147async 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
154 renderChatBackgrounds();152 renderChatBackgrounds();
155 highlightLockedBackground();153 highlightLockedBackground();
154 highlightSelectedBackground();
156}155}
157156
158function getBackgroundPath(fileUrl) {157function getBackgroundPath(fileUrl) {
@@ -160,59 +159,55 @@ function getBackgroundPath(fileUrl) {
160}159}
161160
162function highlightLockedBackground() {161function highlightLockedBackground() {
163 $('.bg_example').removeClass('locked');162 $('.bg_example.locked-background').removeClass('locked-background');
164163
165 const lockedBackground = chat_metadata[BG_METADATA_KEY];164 const lockedBackgroundUrl = chat_metadata[BG_METADATA_KEY];
166165
167 if (!lockedBackground) {166 if (lockedBackgroundUrl) {
168 return;167 $('.bg_example').filter(function () {
168 return $(this).data('url') === lockedBackgroundUrl;
169 }).addClass('locked-background');
169 }170 }
170
171 $('.bg_example').each(function () {
172 const url = $(this).data('url');
173 if (url === lockedBackground) {
174 $(this).addClass('locked');
175 }
176 });
177}171}
178172
179/**173/**
180 * Locks the background for the current chat174 * Locks the background for the current chat
181 * @param {Event} e Click event175 * @param {Event|null} event
182 * @returns {string} Empty string
183 */176 */
184function onLockBackgroundClick(e) {177function onLockBackgroundClick(event = null) {
185 e?.stopPropagation();178 if (!getCurrentChatId()) {
186179 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 }
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();
198 highlightLockedBackground();189 highlightLockedBackground();
199 return '';190 toastr.success(t`Background locked for this chat.`);
200}191}
201192
202/**193/**
203 * Locks the background for the current chat194 * Unlocks the background for the current chat
204 * @param {Event} e Click event195 * @param {Event|null} _event
205 * @returns {string} Empty string
206 */196 */
207function onUnlockBackgroundClick(e) {197function 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}
214209
215function hasCustomBackground() {210function isChatBackgroundLocked() {
216 return chat_metadata[BG_METADATA_KEY];211 return chat_metadata[BG_METADATA_KEY];
217}212}
218213
@@ -226,54 +221,22 @@ function removeBackgroundMetadata() {
226 saveMetadataDebounced();221 saveMetadataDebounced();
227}222}
228223
229function 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
240function unsetCustomBackground() {
241 $('#bg_custom').css('background-image', 'none');
242}
243
244function onSelectBackgroundClick() {224function 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 }
252227
253 // Automatically lock the background if it's custom or other background is locked228 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
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
271 // Fetching to browser memory to reduce flicker238 // Update UI highlights to reflect the changes.
272 fetch(backgroundUrl).then(() => {239 highlightSelectedBackground();
273 setBackground(bgFile, relativeBgImage);
274 }).catch(() => {
275 console.log('Background could not be set: ' + backgroundUrl);
276 });
277}240}
278241
279async function onCopyToSystemBackgroundClick(e) {242async function onCopyToSystemBackgroundClick(e) {
@@ -448,7 +411,6 @@ async function onDeleteBackgroundClick(e) {
448411
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 }
454416
@@ -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}
550514
@@ -620,7 +584,10 @@ async function resolveImageUrl(bg, isCustom) {
620}584}
621585
622async function setBackground(bg, url) {586async 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 }
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 type715 * @param {string} fitting Fitting type
749 */716 */
750function setFittingClass(fitting) {717function 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}
757724
725function 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
758function onBackgroundFilterInput() {739function 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 }));