├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── CHANGELOG.md
├── CollapsibleUI.plugin.js
├── LICENSE
├── README.md
└── eslint.config.mjs
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: programmer2514
2 | patreon: BenjaminPryor
3 | ko_fi: benjaminpryor
4 | custom: [
5 | "https://paypal.me/BenjaminJPryor"
6 | ]
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. Windows 10, Linux Mint]
28 | - Discord Version: [e.g. Stable, PTB, Canary]
29 | - Enabled Theme(s): [e.g. ClearVision, HorizontalServerList]
30 | - (OPTIONAL) Enabled Plugins: [e.g. BDFDB, CallTimeCounter, GameActivityToggle]
31 |
32 | **Additional context**
33 | Add any other context about the problem here.
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 |
3 | node_modules/
4 | package-lock.json
5 | package.json
6 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CollapsibleUI Patch Notes
2 |
3 | ### v12.2.4:
4 | * Fixed user area being cut off
5 | * Fixed a small visual glitch caused by collapsing the channel list
6 | * Improved UIRefreshRefresh compatibility
7 |
8 | ### v12.2.3:
9 | * Fixed user profile compatibility issue with FullscreenToggle plugin
10 |
11 | ### v12.2.2:
12 | * Fixed leftover spacing when collapsing button groups
13 |
14 | ### v12.2.1:
15 | * Fixed a tiny visual inconsistency
16 |
17 | ### v12.2.0:
18 | * Added UIRefreshRefresh compatibility
19 | * Fixed visual glitch when collapsing forum popout
20 |
21 | ### v12.1.1:
22 | * Prevented hiding members list/user profile buttons while they are collapsed
23 | * Fixed crash when trying to collapse all toolbar buttons
24 | * Fixed size collapse not working on some elements
25 | * Fixed several minor styling issues
26 |
27 | ### v12.1.0:
28 | * Fixed for latest Discord version
29 | * Fixed user settings overlapping user profile picture when channel list is collapsed
30 | * Fixed Horizontal Server List compatibility
31 | * Removed static class references
32 |
33 | ### v12.0.0:
34 | * Updated to work with Discord UI refresh (no longer works on old Discord UI)
35 | * Fixed call container buttons being cut off when window is too small
36 | * More visual tweaks for UI consistency
37 | * Removed obsolete advanced settings
38 |
39 | ### v11.0.2:
40 | * Added FullscreenToggle compatibility
41 |
42 | ### v11.0.1:
43 | * Fixed cut-off Message Input on some themes
44 | * Fixed Message Input buttons not being spaced correctly with send message button enabled
45 | * Fixed emoji suggestions not showing in Message Input
46 | * Fixed incorrect Members List styling
47 | * Fixed Channel List offset while in fullscreen calls
48 | * Fixed incompatibility with GameActivityToggle and InvisibleTyping
49 | * Fixed numerical settings being incorrectly stored as strings
50 |
51 | ### v11.0.0:
52 | * Completely re-wrote plugin from the ground up for performance and stability
53 | * Greatly increased plugin\'s overall performance
54 | * Greatly decreased plugin\'s size on disk
55 | * Switched away from direct DOM manipulation wherever possible
56 | * Refactored style routines to reduce reliance on MutationObservers
57 | * Plugin now caches styles, settings, and webpack modules to decrease load times
58 | * Settings update routines have been changed to reduce the number of disk writes
59 | * Keyboard shortcuts can now be whatever you want and are not limited to standard patterns
60 | * Size Collapse has been rewritten using media queries and now does not affect button states
61 | * Expand on Hover is no longer a requirement for Size Collapse (though it is still recommended)
62 | * Resizable panels can now be resized by clicking-and-dragging anywhere on the edge of the panel
63 | * The activities panel, search panel, and forum popout can now be resized and collapsed
64 | * The floating panels setting has been reworked for increased customizability
65 | * Message bar is now capable of floating above other UI elements
66 | * Improved out-of-the-box compatibility with other plugins and themes
67 | * Hovered panels will no longer collapse while a right-click/popup menu is open
68 | * Removed locale labels other than English due to inaccurate translations
69 | * Moved Unread DMs Badge feature to its own plugin
70 | * Updated settings layout and added several new options
71 | * Several visual tweaks for UI consistency
72 | * Fixed showing multiple update notifications if plugin is toggled without reloading Discord
73 | * Fixed inconsistent Size Collapse when snapping window dimensions in Windows
74 | * Fixed panels jumping open during transitions on some low-end devices
75 | * Fixed forum popup resizing inconsistently with other UI elements
76 |
77 | ### v10.0.1:
78 | * Fixed settings failing to apply immediately when set
79 |
80 | ### v10.0.0:
81 | * Added the ability to resize the search panel
82 | * Added the ability to resize the forum popout
83 | * Fixed boolean settings being stored as strings
84 | * Fixed server voice channel being detected as call window
85 | * Fixed forum channels being cut off when channel/members lists are resized too wide
86 |
87 | ### v9.1.4:
88 | * Switched to BdApi for stylesheet handling
89 | * Fixed profile effects and empty members list displaying backwards
90 | * Improved compatibility with DateViewer, MemberCount, and HorizontalServerList
91 |
92 | ### v9.1.3:
93 | * Fixed profile panel failing to collapse on latest Discord update
94 |
95 | ### v9.1.2:
96 | * Fixed plugin failing to load when profile panel is unloaded
97 |
98 | ### v9.1.1:
99 | * Hotfix for newest Discord release
100 | * Fix for ImageUtilities compatibility
101 |
102 | ### v9.1.0:
103 | * Fix for newest Discord release (breaks plugin on Discord versions <360320)
104 | * Message bar no longer collapses when uploading attachments or using the emoji picker
105 |
106 | ### v9.0.2:
107 | * Fixed plugin crashing on MacOS
108 | * Fixed plugin failing to load in forum channels
109 | * Added Quests compatibility
110 |
111 | ### v9.0.0:
112 | * Plugin no longer depends on ZeresPluginLibrary
113 | * Greatly increased robustness against breaking with Discord updates
114 | * Reworked plugin settings and changed defaults
115 | * Decreased plugin size and increased runtime speed
116 | * Updated translations for increased accuracy and consistency
117 | * Added compatibility for MemberCount and CompleteTimestamps
118 | * Fixed channel list failing to collapse/resize
119 | * Fixed VC buttons shrinking when channel list is resized
120 |
121 | ### v8.5.0:
122 | * Fixed profile panel and settings buttons on latest update
123 | * Fixed plugin failing to load in thread channels
124 |
125 | ### v8.4.9:
126 | * Fixed Members List occasionally reversing itself
127 |
128 | ### v8.4.8:
129 | * Hotfix for newest Discord release (breaks plugin on Discord versions <325120)
130 |
131 | ### v8.4.7:
132 | * Fixed grey bar at bottom of screen when zooming out in a fullscreen/server call
133 |
134 | ### v8.4.6:
135 | * Hotfix for newest Discord release (breaks plugin on Discord versions <322979)
136 |
137 | ### v8.4.5:
138 | * Hotfix for newest Discord release (breaks plugin on Discord versions <317617)
139 |
140 | ### v8.4.4:
141 | * Hotfix for newest Discord release (breaks plugin on Discord versions <315866)
142 |
143 | ### v8.4.3:
144 | * Fixed unnecessary console spam
145 | * Updated outdated code
146 |
147 | ### v8.4.2:
148 | * Fixed dynamically uncollapsed elements collapsing when switching servers/channels
149 | * Fixed profile panel briefly jumping open when switching DMs
150 |
151 | ### v8.4.1:
152 | * Hotfix for newest Discord release (breaks plugin on Discord versions <309513)
153 |
154 | ### v8.4.0:
155 | * Hotfix for newest Discord release (breaks plugin on Discord versions <304187)
156 | * Fixed some elements of new profiles being shown reversed
157 | * Fixed call container not filling available space while in fullscreen
158 | * Standardized code formatting using ESLint + Stylistic
159 | * Updated deprecated code
160 |
161 | ### v8.3.2:
162 | * Fixed cut-off message bar buttons in discord PTB and Canary
163 |
164 | ### v8.3.1:
165 | * Fixed broken user profile button in latest Discord update
166 |
167 | ### v8.3.0:
168 | * Hotfix for newest Discord release (breaks plugin on Discord versions <279687)
169 |
170 | ### v8.2.0:
171 | * Updated Russian translation - Thank you @vanja-san
172 | * Fixed plugin not working in forum channels
173 | * Patched a Discord bug with forum channels being cut off by Members List
174 | * Minor code changes
175 |
176 | ### v8.1.2:
177 | * Hopefully fixed (or at least improved) Members List briefly jumping open on channel switch
178 | * More performance improvements
179 |
180 | ### v8.1.1:
181 | * Fixed floating Server List not properly filling vertical space
182 |
183 | ### v8.1.0:
184 | * Fix for even more Discord class/element changes
185 | * The persistent DM badge is now disabled by default
186 | * Fixed Members List offset issue when UI transitions are disabled
187 | * Improved load times and removed unnecessary resource utilization
188 | * Floating Dynamic Uncollapse will now be disabled if Collapsed Element Distance is not equal to 0
189 |
190 | ### v8.0.0:
191 | * Fix for more Discord class/element changes
192 | * Fixed elements occasionally collapsing on scroll
193 | * Made User Profile panel resizable
194 | * Updated plugin icons to match Discord's new theme more closely
195 | * Made uncollapsed elements float instead of shifting other elements over
196 | * Added a persistent badge in the top-left showing a total of unread DMs
197 |
198 | ### v7.4.2:
199 | * Fix for recent Discord sweeping classes/elements changes
200 |
201 | ### v7.4.1:
202 | * Hotfix for newest Discord release (breaks plugin on Discord versions <238110)
203 | * Fixed Call Container button appearing when it shouldn\'t
204 | * Improved compatibility with certain themes
205 |
206 | ### v7.4.0:
207 | * Updated to support newest Discord release (breaks plugin on Discord versions <237546)
208 | * Bumped settings version and cleaned up old JSON
209 | * Fixed Members List not resizing correctly in GCs
210 | * Fixed broken transitions
211 | * Added DateViewer compatibility
212 |
213 | ### v7.3.0:
214 | * Fixed dynamic handling of user profile popout
215 | * Made members list resizable
216 | * Reformatted plugin code
217 |
218 | ### v7.2.4:
219 | * Fixed plugin reloading when user presses shift while hovering the mouse over certain messages
220 | * Updated classes to work with the new themed user profiles
221 |
222 | ### v7.2.3:
223 | * Fixed plugin occasionally failing to reload when switching channels/accounts
224 | * Clarified autocollapse dependencies
225 |
226 | ### v7.2.2:
227 | * Fixed residual styles on message bar buttons on plugin termination/reload
228 | * Added donation links
229 |
230 | ### v7.2.1:
231 | * Reworked code formatting to reduce size and increase readability
232 |
233 | ### v7.2.0:
234 | * Added a fudge factor to collapsible button panels (should decrease jitter)
235 | * Introduced additional advanced settings to control the message bar buttons
236 | * Collapsible button panels are now bound to dynamic uncollapse and its corresponding constraints
237 |
238 | ### v7.1.2:
239 | * Added an outdated plugin warning for future updates
240 |
241 | ### v7.1.1:
242 | * Made message bar buttons collapsible
243 |
244 | ### v7.1.0:
245 | * Fixed plugin crashing Discord when the inspect tool is opened
246 | * Updated to support newest Discord release (breaks plugin on Discord versions <177136)
247 |
248 | ### v7.0.6:
249 | * Removed unnecessary channel resize handle due to buggy rendering
250 | * Fixed channel list with a custom width stuttering when switching channels
251 | * Improved responsiveness of channel list resizing
252 |
253 | ### v7.0.5:
254 | * Fixed unnecessary blank space in server call area
255 |
256 | ### v7.0.4:
257 | * Fixed call area not maintaining custom size when switching between channels
258 | * Fixed channel list expanding unexpectedly on UI refresh if set to a custom width
259 |
260 | ### v7.0.3:
261 | * Fixed message bar autocollapsing when it is not supposed to
262 |
263 | ### v7.0.2:
264 | * Prevented message bar autocollapsing while user is actively typing a message
265 |
266 | ### v7.0.1:
267 | * Fixed full toolbar autocollapse functionality
268 |
269 | ### v7.0.0
270 | * Added full support for User Profile popout
271 | * Completely refactored all plugin code
272 |
273 | ### v6.6.1:
274 | * Tweaked user profile toolbar icon
275 | * Fixed yet another BDFDB incompatibility issue
276 |
277 | ### v6.6.0:
278 | * Separated collapsed states of members list and user profile
279 | * Clarified several settings options
280 | * Changed plugin startup method to work with Canary
281 | * Fixed plugin not loading immediately when first enabled
282 |
283 | ### v6.5.2:
284 | * Fixed several overflow errors with user area and channel list
285 |
286 | ### v6.5.1:
287 | * Fixed minor issues with User Profile panel
288 | * Prevented plugin rarely making server list completely inaccessible
289 | * Removed accidental console spam
290 | * Condensed changelog to save space
291 |
292 | ### v6.5.0:
293 | * Added support for the new User Profile panel
294 |
295 | ### v6.4.2:
296 | * Improved plugin persistence (again)
297 | * Fixed SplitLargeMessages incompatibility
298 | * Cleaned up and refactored some code
299 |
300 | ### v6.4.1:
301 | * Cleaned up method of getting plugin instance
302 | * Fixed scrollbar issue when collapsing user area
303 | * Reworked method for removing Discord's default Members List button
304 |
305 | ### v6.4.0:
306 | * Reduced number of mutationObservers
307 | * Changed plugin persistence algorithm (should be much more consistent)
308 | * Compatibility fix for ServerFolders
309 | * Introduced new conditional autocollapse option
310 | * Removed several "magic numbers" to improve code readability
311 |
312 | ### v6.3.2:
313 | * Fixed members list not collapsing after a message search
314 |
315 | ### v6.3.1:
316 | * Fixed patch notes
317 |
318 | ### v6.3.0:
319 | * Fixed channel list margin remaining in fullscreen mode
320 | * Fixed Members List button functionality in forum channels
321 | * Fixed rare issue where tooltips would get stuck open
322 | * Increased fidelity of toolbar insertion
323 | * Overhauled dynamic uncollapse settings (reset dynamic uncollapse distance)
324 |
325 | ### v6.2.0:
326 | * Fixed resizable channel list on latest update
327 | * Fixed plugin failing to load on initial app startup
328 | * Prevented members list from auto-collapsing when user popout is open
329 |
330 | ### v6.1.3:
331 | * Fixed settings buttons not collapsing when a non-focused user sends a DM
332 | * Removed some pointless console spam
333 |
334 | ### v6.1.2:
335 | * Fixed keyboard shortcuts messing with non-english keyboard layouts
336 |
337 | ### v6.1.1:
338 | * Fixed several issues introduced in v6.1.0
339 | * Rewrote toolbar insertion code to play better with other plugins
340 | * Fixed BDFDB updates causing plugin to break
341 | * Added support for new Discord forum layout
342 |
343 | ### v6.1.0:
344 | * Replaced all intervals with mutation observers
345 | * Removed reliance on ZeresPluginLibrary logger modification
346 | * Changed inefficient startup behavior
347 | * Fixed crash caused by BDFDB's stupidity
348 | * Plugin should now comply with updated code guidelines
349 |
350 | ### v6.0.1:
351 | * Minor tweaks to code and plugin description
352 |
353 | ### v6.0.0:
354 | * Added customizable keybinds to all actions
355 | * Added ability to auto-collapse elements based on size of Discord window
356 | * Added better compatibility with DevilBro's plugins
357 | * Greatly increased plugin persistence
358 | * Fixed plugin not starting after another plugin is updated
359 | * Significantly refactored code for better modularity
360 | * Removed unnecessary plugin reloading when changing settings
361 | * Removed unnecessary console clutter
362 |
363 | ### v5.7.2:
364 | * Fixed HSL integration
365 |
366 | ### v5.7.1:
367 | * Decreased initial plugin loading time
368 | * Fixed incorrect logic causing elements to not remain collapsed
369 |
370 | ### v5.7.0:
371 | * Added settings option to change behavior of collapsed elements when their corresponding button is disabled
372 | * Greatly improved plugin loading times and stability
373 |
374 | ### v5.6.2:
375 | * Fixed plugin not loading during video call/screenshare when chat is hidden
376 |
377 | ### v5.6.1:
378 | * Improved channel list fix (it actually works now)
379 |
380 | ### v5.6.0:
381 | * Fixed settings button alignment glitch
382 | * Fixed incorrect handling of disabled toolbar buttons
383 | * Fixed channel list being able to resize beyond window limits
384 |
385 | ### v5.5.1:
386 | * Tweaked more settings to improve reactability (resets uncollapse distance and delay)
387 | * Clarified and moved a settings option to make it more usable
388 |
389 | ### v5.5.0:
390 | * Fixed toolbar not initializing while in a call
391 | * Added minimal uncollapse delay, which should improve usability
392 | * Tweaked settings and fixed corruption issue (resets all settings to default)
393 |
394 | ### v5.4.4:
395 | * Fixed user area misalignment with transitions disabled
396 | * Added ChannelDMs compatibility
397 |
398 | ### v5.4.3:
399 | * Fixed settings bar alignment glitch
400 |
401 | ### v5.4.2:
402 | * Fixed visual window bar glitch
403 |
404 | ### v5.4.1:
405 | * Fixed minor syntax errors
406 |
407 | ### v5.4.0:
408 | * Added out-of-the-box compatibility and overrides for Dark Matter theme
409 | * Implemented compatibility fix between Dark Matter and Horizontal Server List
410 |
411 | ### v5.3.0:
412 | * Added additional checks for collapsible objects
413 |
414 | ### v5.2.4:
415 | * Suppressed false code security errors
416 |
417 | ### v5.2.3:
418 | * Fixed unintentional console spam
419 |
420 | ### v5.2.2:
421 | * Fixed incorrect settings indices for Selective Dynamic Uncollapse
422 |
423 | ### v5.2.1:
424 | * Fixed plugin failing to load if a collapsed element does not exist
425 |
426 | ### v5.2.0:
427 | * Fixed plugin breaking on GNU/Linux
428 |
429 | ### v5.1.6:
430 | * Cleaned up code
431 |
432 | ### v5.1.5:
433 | * Stopped relying on aria labels for tooltips
434 |
435 | ### v5.1.4:
436 | * Fixed minor security vulnerability with tooltips
437 |
438 | ### v5.1.3:
439 | * Added KeywordTracker compatibility
440 |
441 | ### v5.1.2:
442 | * Fixed elements not collapsing when their respective button is hidden
443 |
444 | ### v5.1.1:
445 | * Reworked toolbar insertion
446 |
447 | ### v5.1.0:
448 | * Added OldTitleBar compatibility
449 |
450 | ### v5.0.2:
451 | * Fixed more call container issues
452 |
453 | ### v5.0.1:
454 | * Fixed call container issues
455 |
456 | ### v5.0.0:
457 | * Decreased number of writes to the config file
458 | * Fixed plugin animations and events while on a call
459 | * Added ability to reset channel list size to default
460 | * Added ability to selectively enable Dynamic Uncollapse
461 | * Added option to make vanilla Discord toolbar collapsible as well as CollapsibleUI's
462 |
463 | ### v4.4.2:
464 | * Fixed channel list not collapsing
465 |
466 | ### v4.4.1:
467 | * Fixed minor channel list styling error
468 |
469 | ### v4.4.0:
470 | * Made channel list resize state persistent
471 |
472 | ### v4.3.1:
473 | * Fixed small tooltip error
474 |
475 | ### v4.3.0:
476 | * Added language localization
477 |
478 | ### v4.2.0:
479 | * Added new advanced option to leave elements partially uncollapsed
480 |
481 | ### v4.1.4:
482 | * Fixed collapsing call container hiding the toolbar
483 |
484 | ### v4.1.3:
485 | * Fixed user area not fully uncollapsing while in a call
486 |
487 | ### v4.1.2:
488 | * Fixed dynamic enabling of Horizontal Server List
489 | * Added startup/shutdown logging
490 |
491 | ### v4.1.1:
492 | * Finished implementing Horizontal Server List support
493 | * Default settings tweaks (reset dynamic uncollapse distance)
494 |
495 | ### v4.1.0:
496 | * Implemented rudimentary Horizontal Server List support
497 |
498 | ### v4.0.7:
499 | * Used more robust message bar hover detection (fixes some themes)
500 |
501 | ### v4.0.6:
502 | * Prevented sidebars from uncollapsing while hovering over message bar
503 |
504 | ### v4.0.5:
505 | * Fixed window bar dynamic uncollapse
506 |
507 | ### v4.0.4:
508 | * Fixed dynamic uncollapse
509 | * Fixed tooltips not showing
510 |
511 | ### v4.0.3:
512 | * Fixed settings collapse malfunction when in a voice call
513 | * Disabled call area buttons collapsing via settings collapse
514 |
515 | ### v4.0.2:
516 | * Fixed UI elements not collapsing on mouse leaving the window
517 |
518 | ### v4.0.1:
519 | * Fixed patch notes
520 |
521 | ### v4.0.0:
522 | * Added settings panel
523 | * Small animation tweaks
524 | * Added dynamic uncollapse feature
525 | * Made call container collapsible
526 | * With settings collapse enabled, now collapses call area buttons correctly
527 | * Fixed a lot of bugs
528 |
529 | ### v3.0.1:
530 | * Fixed BetterDiscord repo integration
531 |
532 | ### v3.0.0:
533 | * Added GNU/Linux support
534 | * Added theme support
535 | * Added thread support
536 | * Made channel list resizable
537 | * Added collapsible button panel feature
538 | * Added settings options in JSON file for advanced tweaking
539 | * Fixed styles on new Discord update
540 | * Fixed many, many bugs
541 |
542 | ### v2.1.1:
543 | * Fixed plugin auto-update
544 |
545 | ### v2.1.0:
546 | * Added ZeresPluginLibrary support
547 |
548 | ### v2.0.1:
549 | * Adjusted some pixel measurements to prevent cutting off the message bar while typing multiline messages
550 |
551 | ### v2.0.0:
552 | * Added a button to collapse the window title bar
553 | * Updated the button icons to be more consistent
554 | * Finished adding transitions to collapsible elements
555 | * Fixed issues with persistent button states
556 | * Actually fixed plugin crashing on reload
557 | * Fixed handling of plugin being disabled
558 |
559 | ### v1.2.1:
560 | * Improved support for non-english locales
561 | * Improved handling of missing config
562 |
563 | ### v1.2.0:
564 | * Added a button to collapse the message bar
565 | * Added transitions to some elements
566 |
567 | ### v1.1.0:
568 | * Added persistent button states
569 | * Fixed plugin crashing on reload
570 |
571 | ### v1.0.0:
572 | * Initial release
573 |
--------------------------------------------------------------------------------
/CollapsibleUI.plugin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @name CollapsibleUI
3 | * @author programmer2514
4 | * @authorId 563652755814875146
5 | * @description A feature-rich BetterDiscord plugin that reworks the Discord UI to be significantly more modular
6 | * @version 12.2.4
7 | * @donate https://ko-fi.com/benjaminpryor
8 | * @patreon https://www.patreon.com/BenjaminPryor
9 | * @website https://github.com/programmer2514/BetterDiscord-CollapsibleUI
10 | * @source https://github.com/programmer2514/BetterDiscord-CollapsibleUI/raw/refs/heads/main/CollapsibleUI.plugin.js
11 | */
12 |
13 | // Abstract settings calls
14 | const settings = {
15 | get transitionSpeed() { return this._transitionSpeed ?? (this._transitionSpeed = runtime.api.Data.load('transition-speed') ?? 200); },
16 | set transitionSpeed(v) { runtime.api.Data.save('transition-speed', this._transitionSpeed = v); },
17 |
18 | get collapseToolbar() { return this._collapseToolbar ?? (this._collapseToolbar = runtime.api.Data.load('collapse-toolbar') ?? 'cui'); },
19 | set collapseToolbar(v) { runtime.api.Data.save('collapse-toolbar', this._collapseToolbar = v); },
20 |
21 | get collapseSettings() { return this._collapseSettings ?? (this._collapseSettings = runtime.api.Data.load('collapse-settings') ?? true); },
22 | set collapseSettings(v) { runtime.api.Data.save('collapse-settings', this._collapseSettings = v); },
23 |
24 | get messageInputCollapse() { return this._messageInputCollapse ?? (this._messageInputCollapse = runtime.api.Data.load('message-input-collapse') ?? true); },
25 | set messageInputCollapse(v) { runtime.api.Data.save('message-input-collapse', this._messageInputCollapse = v); },
26 |
27 | get keyboardShortcuts() { return this._keyboardShortcuts ?? (this._keyboardShortcuts = runtime.api.Data.load('keyboard-shortcuts') ?? true); },
28 | set keyboardShortcuts(v) { runtime.api.Data.save('keyboard-shortcuts', this._keyboardShortcuts = v); },
29 |
30 | get shortcutList() {
31 | if (!this._shortcutList) {
32 | let shortcuts = runtime.api.Data.load('shortcut-list') ?? [['Alt', 's'], ['Alt', 'c'], ['Alt', 'm'], ['Alt', 'p'], ['Alt', 'i'], ['Alt', 'w'], ['Alt', 'v'], ['Alt', 'u'], ['Alt', 'q'], ['Alt', 'f'], ['Alt', 'a']];
33 | this._shortcutList = [
34 | new Set(shortcuts[0]),
35 | new Set(shortcuts[1]),
36 | new Set(shortcuts[2]),
37 | new Set(shortcuts[3]),
38 | new Set(shortcuts[4]),
39 | new Set(shortcuts[5]),
40 | new Set(shortcuts[6]),
41 | new Set(shortcuts[7]),
42 | new Set(shortcuts[8]),
43 | new Set(shortcuts[9]),
44 | new Set(shortcuts[10]),
45 | ];
46 | }
47 | return this._shortcutList;
48 | },
49 | set shortcutList(v) {
50 | runtime.api.Data.save('shortcut-list', v);
51 | this._shortcutList = [
52 | new Set(v[0]),
53 | new Set(v[1]),
54 | new Set(v[2]),
55 | new Set(v[3]),
56 | new Set(v[4]),
57 | new Set(v[5]),
58 | new Set(v[6]),
59 | new Set(v[7]),
60 | new Set(v[8]),
61 | new Set(v[9]),
62 | new Set(v[10]),
63 | ];
64 | },
65 |
66 | get collapseDisabledButtons() { return this._collapseDisabledButtons ?? (this._collapseDisabledButtons = runtime.api.Data.load('collapse-disabled-buttons') ?? false); },
67 | set collapseDisabledButtons(v) { runtime.api.Data.save('collapse-disabled-buttons', this._collapseDisabledButtons = v); },
68 |
69 | get buttonIndexes() { return this._buttonIndexes ?? (this._buttonIndexes = runtime.api.Data.load('button-indexes') ?? [1, 2, 4, 5, 3, 0, 9, 0, 6, 7, 8]); },
70 | set buttonIndexes(v) { runtime.api.Data.save('button-indexes', this._buttonIndexes = v); },
71 |
72 | get floatingPanels() { return this._floatingPanels ?? (this._floatingPanels = runtime.api.Data.load('floating-panels') ?? true); },
73 | set floatingPanels(v) { runtime.api.Data.save('floating-panels', this._floatingPanels = v); },
74 |
75 | get floatingEnabled() { return this._floatingEnabled ?? (this._floatingEnabled = runtime.api.Data.load('floating-enabled') ?? ['hover', 'hover', 'hover', 'hover', 'hover', 'hover', null, null, 'hover', 'hover', 'hover']); },
76 | set floatingEnabled(v) { runtime.api.Data.save('floating-enabled', this._floatingEnabled = v); },
77 |
78 | get expandOnHover() { return this._expandOnHover ?? (this._expandOnHover = runtime.api.Data.load('expand-on-hover') ?? true); },
79 | set expandOnHover(v) { runtime.api.Data.save('expand-on-hover', this._expandOnHover = v); },
80 |
81 | get expandOnHoverEnabled() { return this._expandOnHoverEnabled ?? (this._expandOnHoverEnabled = runtime.api.Data.load('expand-on-hover-enabled') ?? [true, true, true, true, true, true, true, true, true, true, true]); },
82 | set expandOnHoverEnabled(v) { runtime.api.Data.save('expand-on-hover-enabled', this._expandOnHoverEnabled = v); },
83 |
84 | get sizeCollapse() { return this._sizeCollapse ?? (this._sizeCollapse = runtime.api.Data.load('size-collapse') ?? false); },
85 | set sizeCollapse(v) { runtime.api.Data.save('size-collapse', this._sizeCollapse = v); },
86 |
87 | get sizeCollapseThreshold() { return this._sizeCollapseThreshold ?? (this._sizeCollapseThreshold = runtime.api.Data.load('size-collapse-threshold') ?? [500, 600, 950, 1200, 400, 200, 550, 400, 950, 950, 950]); },
88 | set sizeCollapseThreshold(v) { runtime.api.Data.save('size-collapse-threshold', this._sizeCollapseThreshold = v); },
89 |
90 | get conditionalCollapse() { return this._conditionalCollapse ?? (this._conditionalCollapse = runtime.api.Data.load('conditional-collapse') ?? false); },
91 | set conditionalCollapse(v) { runtime.api.Data.save('conditional-collapse', this._conditionalCollapse = v); },
92 |
93 | get collapseConditionals() { return this._collapseConditionals ?? (this._collapseConditionals = runtime.api.Data.load('collapse-conditionals') ?? ['', '', '', '', '', '', '', '', '', '', '']); },
94 | set collapseConditionals(v) { runtime.api.Data.save('collapse-conditionals', this._collapseConditionals = v); },
95 |
96 | get collapseSize() { return this._collapseSize ?? (this._collapseSize = runtime.api.Data.load('collapse-size') ?? 0); },
97 | set collapseSize(v) { runtime.api.Data.save('collapse-size', this._collapseSize = v); },
98 |
99 | get buttonCollapseFudgeFactor() { return this._buttonCollapseFudgeFactor ?? (this._buttonCollapseFudgeFactor = runtime.api.Data.load('button-collapse-fudge-factor') ?? 10); },
100 | set buttonCollapseFudgeFactor(v) { runtime.api.Data.save('button-collapse-fudge-factor', this._buttonCollapseFudgeFactor = v); },
101 |
102 | get expandOnHoverFudgeFactor() { return this._expandOnHoverFudgeFactor ?? (this._expandOnHoverFudgeFactor = runtime.api.Data.load('expand-on-hover-fudge-factor') ?? 15); },
103 | set expandOnHoverFudgeFactor(v) { runtime.api.Data.save('expand-on-hover-fudge-factor', this._expandOnHoverFudgeFactor = v); },
104 |
105 | get messageInputButtonWidth() { return this._messageInputButtonWidth ?? (this._messageInputButtonWidth = runtime.api.Data.load('message-input-button-width') ?? 40); },
106 | set messageInputButtonWidth(v) { runtime.api.Data.save('message-input-button-width', this._messageInputButtonWidth = v); },
107 |
108 | get toolbarElementMaxWidth() { return this._toolbarElementMaxWidth ?? (this._toolbarElementMaxWidth = runtime.api.Data.load('toolbar-element-max-width') ?? 400); },
109 | set toolbarElementMaxWidth(v) { runtime.api.Data.save('toolbar-element-max-width', this._toolbarElementMaxWidth = v); },
110 |
111 | get userAreaMaxHeight() { return this._userAreaMaxHeight ?? (this._userAreaMaxHeight = runtime.api.Data.load('user-area-max-height') ?? 420); },
112 | set userAreaMaxHeight(v) { runtime.api.Data.save('user-area-max-height', this._userAreaMaxHeight = v); },
113 |
114 | get buttonsActive() { return this._buttonsActive ?? (this._buttonsActive = runtime.api.Data.load('buttons-active') ?? [true, true, true, true, true, true, true, true, true, true, true]); },
115 | set buttonsActive(v) { runtime.api.Data.save('buttons-active', this._buttonsActive = v); },
116 |
117 | get channelListWidth() { return this._channelListWidth ?? (this._channelListWidth = runtime.api.Data.load('channel-list-width') ?? 240); },
118 | set channelListWidth(v) { runtime.api.Data.save('channel-list-width', this._channelListWidth = v); },
119 |
120 | get membersListWidth() { return this._membersListWidth ?? (this._membersListWidth = runtime.api.Data.load('members-list-width') ?? 240); },
121 | set membersListWidth(v) { runtime.api.Data.save('members-list-width', this._membersListWidth = v); },
122 |
123 | get userProfileWidth() { return this._userProfileWidth ?? (this._userProfileWidth = runtime.api.Data.load('user-profile-width') ?? 340); },
124 | set userProfileWidth(v) { runtime.api.Data.save('user-profile-width', this._userProfileWidth = v); },
125 |
126 | get searchPanelWidth() { return this._searchPanelWidth ?? (this._searchPanelWidth = runtime.api.Data.load('search-panel-width') ?? 418); },
127 | set searchPanelWidth(v) { runtime.api.Data.save('search-panel-width', this._searchPanelWidth = v); },
128 |
129 | get forumPopoutWidth() { return this._forumPopoutWidth ?? (this._forumPopoutWidth = runtime.api.Data.load('forum-popout-width') ?? 450); },
130 | set forumPopoutWidth(v) { runtime.api.Data.save('forum-popout-width', this._forumPopoutWidth = v); },
131 |
132 | get activityPanelWidth() { return this._activityPanelWidth ?? (this._activityPanelWidth = runtime.api.Data.load('activity-panel-width') ?? 360); },
133 | set activityPanelWidth(v) { runtime.api.Data.save('activity-panel-width', this._activityPanelWidth = v); },
134 |
135 | get defaultChannelListWidth() { return this._defaultChannelListWidth ?? (this._defaultChannelListWidth = runtime.api.Data.load('default-channel-list-width') ?? 240); },
136 | set defaultChannelListWidth(v) { runtime.api.Data.save('default-channel-list-width', this._defaultChannelListWidth = v); },
137 |
138 | get defaultMembersListWidth() { return this._defaultMembersListWidth ?? (this._defaultMembersListWidth = runtime.api.Data.load('default-members-list-width') ?? 240); },
139 | set defaultMembersListWidth(v) { runtime.api.Data.save('default-members-list-width', this._defaultMembersListWidth = v); },
140 |
141 | get defaultUserProfileWidth() { return this._defaultUserProfileWidth ?? (this._defaultUserProfileWidth = runtime.api.Data.load('default-user-profile-width') ?? 340); },
142 | set defaultUserProfileWidth(v) { runtime.api.Data.save('default-user-profile-width', this._defaultUserProfileWidth = v); },
143 |
144 | get defaultSearchPanelWidth() { return this._defaultSearchPanelWidth ?? (this._defaultSearchPanelWidth = runtime.api.Data.load('default-search-panel-width') ?? 418); },
145 | set defaultSearchPanelWidth(v) { runtime.api.Data.save('default-search-panel-width', this._defaultSearchPanelWidth = v); },
146 |
147 | get defaultForumPopoutWidth() { return this._defaultForumPopoutWidth ?? (this._defaultForumPopoutWidth = runtime.api.Data.load('default-forum-popout-width') ?? 450); },
148 | set defaultForumPopoutWidth(v) { runtime.api.Data.save('default-forum-popout-width', this._defaultForumPopoutWidth = v); },
149 |
150 | get defaultActivityPanelWidth() { return this._defaultActivityPanelWidth ?? (this._defaultActivityPanelWidth = runtime.api.Data.load('default-activity-panel-width') ?? 360); },
151 | set defaultActivityPanelWidth(v) { runtime.api.Data.save('default-activity-panel-width', this._defaultActivityPanelWidth = v); },
152 | };
153 |
154 | // Define plugin changelog and settings panel layout
155 | const config = {
156 | changelog: [
157 | {
158 | title: '12.2.4',
159 | type: 'added',
160 | items: [
161 | 'Fixed user area being cut off',
162 | 'Fixed a small visual glitch caused by collapsing the channel list',
163 | 'Improved UIRefreshRefresh compatibility',
164 | ],
165 | },
166 | {
167 | title: '1.0.0 - 12.2.3',
168 | type: 'added',
169 | items: [
170 | 'See the full changelog here: https://programmer2514.github.io/?l=cui-changelog',
171 | ],
172 | },
173 | ],
174 | settings: [
175 | {
176 | type: 'category',
177 | id: 'main-group',
178 | name: 'Main',
179 | collapsible: true,
180 | shown: true,
181 | settings: [
182 | {
183 | type: 'number',
184 | id: 'transitionSpeed',
185 | name: 'UI Transition Speed (ms)',
186 | note: 'Sets the speed of UI animations. Set to 0 to disable transitions',
187 | get value() { return settings.transitionSpeed; },
188 | },
189 | {
190 | type: 'dropdown',
191 | id: 'collapseToolbar',
192 | name: 'Collapse Toolbar Buttons',
193 | note: 'Automatically collapse the top-right toolbar buttons',
194 | get value() { return settings.collapseToolbar; },
195 | options: [
196 | {
197 | label: 'None',
198 | value: false,
199 | },
200 | {
201 | label: 'Just CollapsibleUI',
202 | value: 'cui',
203 | },
204 | {
205 | label: 'All',
206 | value: 'all',
207 | },
208 | ],
209 | },
210 | {
211 | type: 'switch',
212 | id: 'collapseSettings',
213 | name: 'Collapse Settings',
214 | note: 'Automatically collapse the bottom-left settings buttons',
215 | get value() { return settings.collapseSettings; },
216 | },
217 | {
218 | type: 'switch',
219 | id: 'messageInputCollapse',
220 | name: 'Collapse Message Input Buttons',
221 | note: 'Automatically collapse the GIF/sticker/emoji/gift buttons',
222 | get value() { return settings.messageInputCollapse; },
223 | },
224 | ],
225 | },
226 | {
227 | type: 'category',
228 | id: 'keyboard-shortcuts-group',
229 | name: 'Keyboard Shortcuts',
230 | collapsible: true,
231 | shown: false,
232 | settings: [
233 | {
234 | type: 'switch',
235 | id: 'keyboardShortcuts',
236 | name: 'Keyboard Shortcuts',
237 | note: 'Collapse UI panels using keyboard shortcuts',
238 | get value() { return settings.keyboardShortcuts; },
239 | },
240 | {
241 | type: 'keybind',
242 | id: 'server-list-shortcut',
243 | name: 'Toggle Server List',
244 | get value() { return [...settings.shortcutList[constants.I_SERVER_LIST]]; },
245 | },
246 | {
247 | type: 'keybind',
248 | id: 'channel-list-shortcut',
249 | name: 'Toggle Channel List',
250 | get value() { return [...settings.shortcutList[constants.I_CHANNEL_LIST]]; },
251 | },
252 | {
253 | type: 'keybind',
254 | id: 'members-list-shortcut',
255 | name: 'Toggle Members List',
256 | get value() { return [...settings.shortcutList[constants.I_MEMBERS_LIST]]; },
257 | },
258 | {
259 | type: 'keybind',
260 | id: 'user-profile-shortcut',
261 | name: 'Toggle User Profile',
262 | get value() { return [...settings.shortcutList[constants.I_USER_PROFILE]]; },
263 | },
264 | {
265 | type: 'keybind',
266 | id: 'message-input-shortcut',
267 | name: 'Toggle Message Input',
268 | get value() { return [...settings.shortcutList[constants.I_MESSAGE_INPUT]]; },
269 | },
270 | {
271 | type: 'keybind',
272 | id: 'window-bar-shortcut',
273 | name: 'Toggle Window Bar',
274 | get value() { return [...settings.shortcutList[constants.I_WINDOW_BAR]]; },
275 | },
276 | {
277 | type: 'keybind',
278 | id: 'call-window-shortcut',
279 | name: 'Toggle Call Window',
280 | get value() { return [...settings.shortcutList[constants.I_CALL_WINDOW]]; },
281 | },
282 | {
283 | type: 'keybind',
284 | id: 'user-area-shortcut',
285 | name: 'Toggle User Area',
286 | get value() { return [...settings.shortcutList[constants.I_USER_AREA]]; },
287 | },
288 | {
289 | type: 'keybind',
290 | id: 'search-panel-shortcut',
291 | name: 'Toggle Search Panel',
292 | get value() { return [...settings.shortcutList[constants.I_SEARCH_PANEL]]; },
293 | },
294 | {
295 | type: 'keybind',
296 | id: 'forum-popout-shortcut',
297 | name: 'Toggle Forum Popout',
298 | get value() { return [...settings.shortcutList[constants.I_FORUM_POPOUT]]; },
299 | },
300 | {
301 | type: 'keybind',
302 | id: 'activity-panel-shortcut',
303 | name: 'Toggle Activity Panel',
304 | get value() { return [...settings.shortcutList[constants.I_ACTIVITY_PANEL]]; },
305 | },
306 | ],
307 | },
308 | {
309 | type: 'category',
310 | id: 'toolbar-buttons-group',
311 | name: 'Toolbar Buttons',
312 | collapsible: true,
313 | shown: false,
314 | settings: [
315 | {
316 | type: 'switch',
317 | id: 'collapseDisabledButtons',
318 | name: 'Disabled Buttons Stay Collapsed?',
319 | note: 'Panels with disabled toggle buttons will keep their toggled state. If disabled, they will default to open',
320 | get value() { return settings.collapseDisabledButtons; },
321 | },
322 | {
323 | type: 'slider',
324 | id: 'server-list-button-index',
325 | name: 'Server List Button',
326 | note: 'Sets the order of the Server List toolbar button. Set to 0 to disable',
327 | get value() { return settings.buttonIndexes[constants.I_SERVER_LIST]; },
328 | min: 0,
329 | max: 11,
330 | step: 1,
331 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
332 | },
333 | {
334 | type: 'slider',
335 | id: 'channel-list-button-index',
336 | name: 'Channel List Button',
337 | note: 'Sets the order of the Channel List toolbar button. Set to 0 to disable',
338 | get value() { return settings.buttonIndexes[constants.I_CHANNEL_LIST]; },
339 | min: 0,
340 | max: 11,
341 | step: 1,
342 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
343 | },
344 | {
345 | type: 'slider',
346 | id: 'members-list-button-index',
347 | name: 'Members List Button',
348 | note: 'Sets the order of the Members List toolbar button. Set to 0 to disable',
349 | get value() { return settings.buttonIndexes[constants.I_MEMBERS_LIST]; },
350 | min: 0,
351 | max: 11,
352 | step: 1,
353 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
354 | },
355 | {
356 | type: 'slider',
357 | id: 'user-profile-button-index',
358 | name: 'User Profile Button',
359 | note: 'Sets the order of the User Profile toolbar button. Set to 0 to disable',
360 | get value() { return settings.buttonIndexes[constants.I_USER_PROFILE]; },
361 | min: 0,
362 | max: 11,
363 | step: 1,
364 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
365 | },
366 | {
367 | type: 'slider',
368 | id: 'message-input-button-index',
369 | name: 'Message Input Button',
370 | note: 'Sets the order of the Message Input toolbar button. Set to 0 to disable',
371 | get value() { return settings.buttonIndexes[constants.I_MESSAGE_INPUT]; },
372 | min: 0,
373 | max: 11,
374 | step: 1,
375 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
376 | },
377 | {
378 | type: 'slider',
379 | id: 'window-bar-button-index',
380 | name: 'Window Bar Button',
381 | note: 'Sets the order of the Window Bar toolbar button. Set to 0 to disable',
382 | get value() { return settings.buttonIndexes[constants.I_WINDOW_BAR]; },
383 | min: 0,
384 | max: 11,
385 | step: 1,
386 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
387 | },
388 | {
389 | type: 'slider',
390 | id: 'call-window-button-index',
391 | name: 'Call Window Button',
392 | note: 'Sets the order of the Call Window toolbar button. Set to 0 to disable',
393 | get value() { return settings.buttonIndexes[constants.I_CALL_WINDOW]; },
394 | min: 0,
395 | max: 11,
396 | step: 1,
397 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
398 | },
399 | {
400 | type: 'slider',
401 | id: 'user-area-button-index',
402 | name: 'User Area Button',
403 | note: 'Sets the order of the User Area toolbar button. Set to 0 to disable',
404 | get value() { return settings.buttonIndexes[constants.I_USER_AREA]; },
405 | min: 0,
406 | max: 11,
407 | step: 1,
408 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
409 | },
410 | {
411 | type: 'slider',
412 | id: 'search-panel-button-index',
413 | name: 'Search Panel Button',
414 | note: 'Sets the order of the Search Panel toolbar button. Set to 0 to disable',
415 | get value() { return settings.buttonIndexes[constants.I_SEARCH_PANEL]; },
416 | min: 0,
417 | max: 11,
418 | step: 1,
419 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
420 | },
421 | {
422 | type: 'slider',
423 | id: 'forum-popout-button-index',
424 | name: 'Forum Popout Button',
425 | note: 'Sets the order of the Forum Popout toolbar button. Set to 0 to disable',
426 | get value() { return settings.buttonIndexes[constants.I_FORUM_POPOUT]; },
427 | min: 0,
428 | max: 11,
429 | step: 1,
430 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
431 | },
432 | {
433 | type: 'slider',
434 | id: 'activity-panel-button-index',
435 | name: 'Activity Panel Button',
436 | note: 'Sets the order of the Activity Panel toolbar button. Set to 0 to disable',
437 | get value() { return settings.buttonIndexes[constants.I_ACTIVITY_PANEL]; },
438 | min: 0,
439 | max: 11,
440 | step: 1,
441 | markers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
442 | },
443 | ],
444 | },
445 | {
446 | type: 'category',
447 | id: 'resizable-panels-group',
448 | name: 'Resizable Panels',
449 | collapsible: true,
450 | shown: false,
451 | settings: [
452 | {
453 | type: 'switch',
454 | id: 'resizable-channel-list',
455 | name: 'Resizable Channel List',
456 | note: 'Resize the channel list by clicking-and-dragging right edge. Right-click to reset width',
457 | get value() { return settings.channelListWidth !== 0; },
458 | },
459 | {
460 | type: 'switch',
461 | id: 'resizable-members-list',
462 | name: 'Resizable Members List',
463 | note: 'Resize the members list by clicking-and-dragging the left edge. Right-click to reset width',
464 | get value() { return settings.membersListWidth !== 0; },
465 | },
466 | {
467 | type: 'switch',
468 | id: 'resizable-user-profile',
469 | name: 'Resizable User Profile',
470 | note: 'Resize the user profile in DMs by clicking-and-dragging the left edge. Right-click to reset width',
471 | get value() { return settings.userProfileWidth !== 0; },
472 | },
473 | {
474 | type: 'switch',
475 | id: 'resizable-search-panel',
476 | name: 'Resizable Search Panel',
477 | note: 'Resize the message search panel by clicking-and-dragging the left edge. Right-click to reset width',
478 | get value() { return settings.searchPanelWidth !== 0; },
479 | },
480 | {
481 | type: 'switch',
482 | id: 'resizable-forum-popout',
483 | name: 'Resizable Forum Popout',
484 | note: 'Resize the thread popup in forum channels by clicking-and-dragging the left edge. Right-click to reset width',
485 | get value() { return settings.forumPopoutWidth !== 0; },
486 | },
487 | {
488 | type: 'switch',
489 | id: 'resizable-activity-panel',
490 | name: 'Resizable Activity Panel',
491 | note: 'Resize the activity panel in the friends list by clicking-and-dragging the left edge. Right-click to reset width',
492 | get value() { return settings.activityPanelWidth !== 0; },
493 | },
494 | ],
495 | },
496 | {
497 | type: 'category',
498 | id: 'floating-panels-group',
499 | name: 'Floating Panels',
500 | collapsible: true,
501 | shown: false,
502 | settings: [
503 | {
504 | type: 'switch',
505 | id: 'floatingPanels',
506 | name: 'Floating Panels',
507 | note: 'Expanded UI panels will float over other panels, instead of moving them out of the way',
508 | get value() { return settings.floatingPanels; },
509 | },
510 | {
511 | type: 'dropdown',
512 | id: 'server-list-floating',
513 | name: 'Server List',
514 | note: 'Server List floats over other panels',
515 | get value() { return settings.floatingEnabled[constants.I_SERVER_LIST]; },
516 | options: [
517 | {
518 | label: 'Never',
519 | value: false,
520 | },
521 | {
522 | label: 'On Hover',
523 | value: 'hover',
524 | },
525 | {
526 | label: 'Always',
527 | value: 'always',
528 | },
529 | ],
530 | },
531 | {
532 | type: 'dropdown',
533 | id: 'channel-list-floating',
534 | name: 'Channel List',
535 | note: 'Channel List floats over other panels',
536 | get value() { return settings.floatingEnabled[constants.I_CHANNEL_LIST]; },
537 | options: [
538 | {
539 | label: 'Never',
540 | value: false,
541 | },
542 | {
543 | label: 'On Hover',
544 | value: 'hover',
545 | },
546 | {
547 | label: 'Always',
548 | value: 'always',
549 | },
550 | ],
551 | },
552 | {
553 | type: 'dropdown',
554 | id: 'members-list-floating',
555 | name: 'Members List',
556 | note: 'Members List floats over other panels',
557 | get value() { return settings.floatingEnabled[constants.I_MEMBERS_LIST]; },
558 | options: [
559 | {
560 | label: 'Never',
561 | value: false,
562 | },
563 | {
564 | label: 'On Hover',
565 | value: 'hover',
566 | },
567 | {
568 | label: 'Always',
569 | value: 'always',
570 | },
571 | ],
572 | },
573 | {
574 | type: 'dropdown',
575 | id: 'user-profile-floating',
576 | name: 'User Profile',
577 | note: 'User Profile floats over other panels',
578 | get value() { return settings.floatingEnabled[constants.I_USER_PROFILE]; },
579 | options: [
580 | {
581 | label: 'Never',
582 | value: false,
583 | },
584 | {
585 | label: 'On Hover',
586 | value: 'hover',
587 | },
588 | {
589 | label: 'Always',
590 | value: 'always',
591 | },
592 | ],
593 | },
594 | {
595 | type: 'dropdown',
596 | id: 'message-input-floating',
597 | name: 'Message Input',
598 | note: 'Message Input floats over other panels',
599 | get value() { return settings.floatingEnabled[constants.I_MESSAGE_INPUT]; },
600 | options: [
601 | {
602 | label: 'Never',
603 | value: false,
604 | },
605 | {
606 | label: 'On Hover',
607 | value: 'hover',
608 | },
609 | {
610 | label: 'Always',
611 | value: 'always',
612 | },
613 | ],
614 | },
615 | {
616 | type: 'dropdown',
617 | id: 'window-bar-floating',
618 | name: 'Window Bar',
619 | note: 'Window Bar floats over other panels',
620 | get value() { return settings.floatingEnabled[constants.I_WINDOW_BAR]; },
621 | options: [
622 | {
623 | label: 'Never',
624 | value: false,
625 | },
626 | {
627 | label: 'On Hover',
628 | value: 'hover',
629 | },
630 | {
631 | label: 'Always',
632 | value: 'always',
633 | },
634 | ],
635 | },
636 | {
637 | type: 'dropdown',
638 | id: 'search-panel-floating',
639 | name: 'Search Panel',
640 | note: 'Search Panel floats over other panels',
641 | get value() { return settings.floatingEnabled[constants.I_SEARCH_PANEL]; },
642 | options: [
643 | {
644 | label: 'Never',
645 | value: false,
646 | },
647 | {
648 | label: 'On Hover',
649 | value: 'hover',
650 | },
651 | {
652 | label: 'Always',
653 | value: 'always',
654 | },
655 | ],
656 | },
657 | {
658 | type: 'dropdown',
659 | id: 'forum-popout-floating',
660 | name: 'Forum Popout',
661 | note: 'Forum Popout floats over other panels',
662 | get value() { return settings.floatingEnabled[constants.I_FORUM_POPOUT]; },
663 | options: [
664 | {
665 | label: 'Never',
666 | value: false,
667 | },
668 | {
669 | label: 'On Hover',
670 | value: 'hover',
671 | },
672 | {
673 | label: 'Always',
674 | value: 'always',
675 | },
676 | ],
677 | },
678 | {
679 | type: 'dropdown',
680 | id: 'activity-panel-floating',
681 | name: 'Activity Panel',
682 | note: 'Activity Panel floats over other panels',
683 | get value() { return settings.floatingEnabled[constants.I_ACTIVITY_PANEL]; },
684 | options: [
685 | {
686 | label: 'Never',
687 | value: false,
688 | },
689 | {
690 | label: 'On Hover',
691 | value: 'hover',
692 | },
693 | {
694 | label: 'Always',
695 | value: 'always',
696 | },
697 | ],
698 | },
699 | ],
700 | },
701 | {
702 | type: 'category',
703 | id: 'expand-on-hover-group',
704 | name: 'Expand on Hover',
705 | collapsible: true,
706 | shown: false,
707 | settings: [
708 | {
709 | type: 'switch',
710 | id: 'expandOnHover',
711 | name: 'Expand on Hover',
712 | note: 'Expands collapsed UI panels when the mouse is near them. Must be enabled for conditional/size collapse to work',
713 | get value() { return settings.expandOnHover; },
714 | },
715 | {
716 | type: 'switch',
717 | id: 'server-list-expand-on-hover',
718 | name: 'Server List',
719 | note: 'Server List expands on hover',
720 | get value() { return settings.expandOnHoverEnabled[constants.I_SERVER_LIST]; },
721 | },
722 | {
723 | type: 'switch',
724 | id: 'channel-list-expand-on-hover',
725 | name: 'Channel List',
726 | note: 'Channel List expands on hover',
727 | get value() { return settings.expandOnHoverEnabled[constants.I_CHANNEL_LIST]; },
728 | },
729 | {
730 | type: 'switch',
731 | id: 'members-list-expand-on-hover',
732 | name: 'Members List',
733 | note: 'Members List expands on hover',
734 | get value() { return settings.expandOnHoverEnabled[constants.I_MEMBERS_LIST]; },
735 | },
736 | {
737 | type: 'switch',
738 | id: 'user-profile-expand-on-hover',
739 | name: 'User Profile',
740 | note: 'User Profile expands on hover',
741 | get value() { return settings.expandOnHoverEnabled[constants.I_USER_PROFILE]; },
742 | },
743 | {
744 | type: 'switch',
745 | id: 'message-input-expand-on-hover',
746 | name: 'Message Input',
747 | note: 'Message Input expands on hover',
748 | get value() { return settings.expandOnHoverEnabled[constants.I_MESSAGE_INPUT]; },
749 | },
750 | {
751 | type: 'switch',
752 | id: 'window-bar-expand-on-hover',
753 | name: 'Window Bar',
754 | note: 'Window Bar expands on hover',
755 | get value() { return settings.expandOnHoverEnabled[constants.I_WINDOW_BAR]; },
756 | },
757 | {
758 | type: 'switch',
759 | id: 'call-window-expand-on-hover',
760 | name: 'Call Window',
761 | note: 'Call Window expands on hover',
762 | get value() { return settings.expandOnHoverEnabled[constants.I_CALL_WINDOW]; },
763 | },
764 | {
765 | type: 'switch',
766 | id: 'user-area-expand-on-hover',
767 | name: 'User Area',
768 | note: 'User Area expands on hover',
769 | get value() { return settings.expandOnHoverEnabled[constants.I_USER_AREA]; },
770 | },
771 | {
772 | type: 'switch',
773 | id: 'search-panel-expand-on-hover',
774 | name: 'Search Panel',
775 | note: 'Search Panel expands on hover',
776 | get value() { return settings.expandOnHoverEnabled[constants.I_SEARCH_PANEL]; },
777 | },
778 | {
779 | type: 'switch',
780 | id: 'forum-popout-expand-on-hover',
781 | name: 'Forum Popout',
782 | note: 'Forum Popout expands on hover',
783 | get value() { return settings.expandOnHoverEnabled[constants.I_FORUM_POPOUT]; },
784 | },
785 | {
786 | type: 'switch',
787 | id: 'activity-panel-expand-on-hover',
788 | name: 'Activity Panel',
789 | note: 'Activity Panel expands on hover',
790 | get value() { return settings.expandOnHoverEnabled[constants.I_ACTIVITY_PANEL]; },
791 | },
792 | ],
793 | },
794 | {
795 | type: 'category',
796 | id: 'size-collapse-group',
797 | name: 'Size Collapse',
798 | collapsible: true,
799 | shown: false,
800 | settings: [
801 | {
802 | type: 'switch',
803 | id: 'sizeCollapse',
804 | name: 'Size Collapse',
805 | note: 'Auto-collapse UI panels based on window size',
806 | get value() { return settings.sizeCollapse; },
807 | },
808 | {
809 | type: 'number',
810 | id: 'server-list-threshold',
811 | name: 'Server List - Width Threshold (px)',
812 | note: 'Window width at which the Server List will collapse. Specifies height if Horizontal Server List is enabled',
813 | get value() { return settings.sizeCollapseThreshold[constants.I_SERVER_LIST]; },
814 | },
815 | {
816 | type: 'number',
817 | id: 'channel-list-threshold',
818 | name: 'Channel List - Width Threshold (px)',
819 | note: 'Window width at which the Channel List will collapse',
820 | get value() { return settings.sizeCollapseThreshold[constants.I_CHANNEL_LIST]; },
821 | },
822 | {
823 | type: 'number',
824 | id: 'members-list-threshold',
825 | name: 'Members List - Width Threshold (px)',
826 | note: 'Window width at which the Members List will collapse',
827 | get value() { return settings.sizeCollapseThreshold[constants.I_MEMBERS_LIST]; },
828 | },
829 | {
830 | type: 'number',
831 | id: 'user-profile-threshold',
832 | name: 'User Profile - Width Threshold (px)',
833 | note: 'Window width at which the User Profile will collapse',
834 | get value() { return settings.sizeCollapseThreshold[constants.I_USER_PROFILE]; },
835 | },
836 | {
837 | type: 'number',
838 | id: 'message-input-threshold',
839 | name: 'Message Input - Height Threshold (px)',
840 | note: 'Window height at which the Message Input will collapse',
841 | get value() { return settings.sizeCollapseThreshold[constants.I_MESSAGE_INPUT]; },
842 | },
843 | {
844 | type: 'number',
845 | id: 'window-bar-threshold',
846 | name: 'Window Bar - Height Threshold (px)',
847 | note: 'Window height at which the Window Bar will collapse',
848 | get value() { return settings.sizeCollapseThreshold[constants.I_WINDOW_BAR]; },
849 | },
850 | {
851 | type: 'number',
852 | id: 'call-window-threshold',
853 | name: 'Call Window - Height Threshold (px)',
854 | note: 'Window height at which the Call Window will collapse',
855 | get value() { return settings.sizeCollapseThreshold[constants.I_CALL_WINDOW]; },
856 | },
857 | {
858 | type: 'number',
859 | id: 'user-area-threshold',
860 | name: 'User Area - Height Threshold (px)',
861 | note: 'Window height at which the User Area will collapse',
862 | get value() { return settings.sizeCollapseThreshold[constants.I_USER_AREA]; },
863 | },
864 | {
865 | type: 'number',
866 | id: 'search-panel-threshold',
867 | name: 'Search Panel - Width Threshold (px)',
868 | note: 'Window width at which the Search Panel will collapse',
869 | get value() { return settings.sizeCollapseThreshold[constants.I_SEARCH_PANEL]; },
870 | },
871 | {
872 | type: 'number',
873 | id: 'forum-popout-threshold',
874 | name: 'Forum Popout - Width Threshold (px)',
875 | note: 'Window width at which the Forum Popout will collapse',
876 | get value() { return settings.sizeCollapseThreshold[constants.I_FORUM_POPOUT]; },
877 | },
878 | {
879 | type: 'number',
880 | id: 'activity-panel-threshold',
881 | name: 'Activity Panel - Width Threshold (px)',
882 | note: 'Window width at which the Activity Panel will collapse',
883 | get value() { return settings.sizeCollapseThreshold[constants.I_ACTIVITY_PANEL]; },
884 | },
885 | ],
886 | },
887 | {
888 | type: 'category',
889 | id: 'conditional-collapse-group',
890 | name: 'Conditional Collapse (Advanced)',
891 | collapsible: true,
892 | shown: false,
893 | settings: [
894 | {
895 | type: 'switch',
896 | id: 'conditionalCollapse',
897 | name: 'Conditional Collapse',
898 | note: 'Auto-collapse UI panels based on custom conditional expression. Overrides size collapse',
899 | get value() { return settings.conditionalCollapse; },
900 | },
901 | {
902 | type: 'text',
903 | id: 'server-list-conditional',
904 | name: 'Server List - Collapse Expression (JS)',
905 | note: 'The Server List will collapse when this expression is true, and expand when it is false',
906 | get value() { return settings.collapseConditionals[constants.I_SERVER_LIST]; },
907 | },
908 | {
909 | type: 'text',
910 | id: 'channel-list-conditional',
911 | name: 'Channel List - Collapse Expression (JS)',
912 | note: 'The Channel List will collapse when this expression is true, and expand when it is false',
913 | get value() { return settings.collapseConditionals[constants.I_CHANNEL_LIST]; },
914 | },
915 | {
916 | type: 'text',
917 | id: 'members-list-conditional',
918 | name: 'Members List - Collapse Expression (JS)',
919 | note: 'The Members List will collapse when this expression is true, and expand when it is false',
920 | get value() { return settings.collapseConditionals[constants.I_MEMBERS_LIST]; },
921 | },
922 | {
923 | type: 'text',
924 | id: 'user-profile-conditional',
925 | name: 'User Profile - Collapse Expression (JS)',
926 | note: 'The User Profile will collapse when this expression is true, and expand when it is false',
927 | get value() { return settings.collapseConditionals[constants.I_USER_PROFILE]; },
928 | },
929 | {
930 | type: 'text',
931 | id: 'message-input-conditional',
932 | name: 'Message Input - Collapse Expression (JS)',
933 | note: 'The Message Input will collapse when this expression is true, and expand when it is false',
934 | get value() { return settings.collapseConditionals[constants.I_MESSAGE_INPUT]; },
935 | },
936 | {
937 | type: 'text',
938 | id: 'window-bar-conditional',
939 | name: 'Window Bar - Collapse Expression (JS)',
940 | note: 'The Window Bar will collapse when this expression is true, and expand when it is false',
941 | get value() { return settings.collapseConditionals[constants.I_WINDOW_BAR]; },
942 | },
943 | {
944 | type: 'text',
945 | id: 'call-window-conditional',
946 | name: 'Call Window - Collapse Expression (JS)',
947 | note: 'The Call Window will collapse when this expression is true, and expand when it is false',
948 | get value() { return settings.collapseConditionals[constants.I_CALL_WINDOW]; },
949 | },
950 | {
951 | type: 'text',
952 | id: 'user-area-conditional',
953 | name: 'User Area - Collapse Expression (JS)',
954 | note: 'The User Area will collapse when this expression is true, and expand when it is false',
955 | get value() { return settings.collapseConditionals[constants.I_USER_AREA]; },
956 | },
957 | {
958 | type: 'text',
959 | id: 'search-panel-conditional',
960 | name: 'Search Panel - Collapse Expression (JS)',
961 | note: 'The Search Panel will collapse when this expression is true, and expand when it is false',
962 | get value() { return settings.collapseConditionals[constants.I_SEARCH_PANEL]; },
963 | },
964 | {
965 | type: 'text',
966 | id: 'forum-popout-conditional',
967 | name: 'Forum Popout - Collapse Expression (JS)',
968 | note: 'The Forum Popout will collapse when this expression is true, and expand when it is false',
969 | get value() { return settings.collapseConditionals[constants.I_FORUM_POPOUT]; },
970 | },
971 | {
972 | type: 'text',
973 | id: 'activity-panel-conditional',
974 | name: 'Activity Panel - Collapse Expression (JS)',
975 | note: 'The Activity Panel will collapse when this expression is true, and expand when it is false',
976 | get value() { return settings.collapseConditionals[constants.I_ACTIVITY_PANEL]; },
977 | },
978 | ],
979 | },
980 | {
981 | type: 'category',
982 | id: 'advanced-group',
983 | name: 'Advanced',
984 | collapsible: true,
985 | shown: false,
986 | settings: [
987 | {
988 | type: 'number',
989 | id: 'collapseSize',
990 | name: 'Collapsed Panel Size (px)',
991 | note: 'The size of UI panels when collapsed',
992 | get value() { return settings.collapseSize; },
993 | },
994 | {
995 | type: 'number',
996 | id: 'buttonCollapseFudgeFactor',
997 | name: 'Button Groups - Collapse Fudge Factor (px)',
998 | note: 'The distance the mouse must be from a set of buttons before they collapse',
999 | get value() { return settings.buttonCollapseFudgeFactor; },
1000 | },
1001 | {
1002 | type: 'number',
1003 | id: 'expandOnHoverFudgeFactor',
1004 | name: 'Expand on Hover - Fudge Factor (px)',
1005 | note: 'The distance the mouse must be from a UI panel before it expands or collapses',
1006 | get value() { return settings.expandOnHoverFudgeFactor; },
1007 | },
1008 | {
1009 | type: 'number',
1010 | id: 'messageInputButtonWidth',
1011 | name: 'Message Input Button - Width (px)',
1012 | note: 'The width of a message input button when expanded',
1013 | get value() { return settings.messageInputButtonWidth; },
1014 | },
1015 | {
1016 | type: 'number',
1017 | id: 'toolbarElementMaxWidth',
1018 | name: 'Toolbar Elements - Max Width (px)',
1019 | note: 'The maximum width of the full toolbar\'s elements when expanded',
1020 | get value() { return settings.toolbarElementMaxWidth; },
1021 | },
1022 | {
1023 | type: 'number',
1024 | id: 'userAreaMaxHeight',
1025 | name: 'User Area - Max Height (px)',
1026 | note: 'The maximum height of the User Area when expanded',
1027 | get value() { return settings.userAreaMaxHeight; },
1028 | },
1029 | {
1030 | type: 'number',
1031 | id: 'defaultChannelListWidth',
1032 | name: 'Channel List - Default Width (px)',
1033 | note: 'The width of the channel list when not actively resized',
1034 | get value() { return settings.defaultChannelListWidth; },
1035 | },
1036 | {
1037 | type: 'number',
1038 | id: 'defaultMembersListWidth',
1039 | name: 'Members List - Default Width (px)',
1040 | note: 'The width of the members list when not actively resized',
1041 | get value() { return settings.defaultMembersListWidth; },
1042 | },
1043 | {
1044 | type: 'number',
1045 | id: 'defaultUserProfileWidth',
1046 | name: 'User Profile - Default Width (px)',
1047 | note: 'The width of the user profile when not actively resized',
1048 | get value() { return settings.defaultUserProfileWidth; },
1049 | },
1050 | {
1051 | type: 'number',
1052 | id: 'defaultSearchPanelWidth',
1053 | name: 'Search Panel - Default Width (px)',
1054 | note: 'The width of the search panel when not actively resized',
1055 | get value() { return settings.defaultSearchPanelWidth; },
1056 | },
1057 | {
1058 | type: 'number',
1059 | id: 'defaultForumPopoutWidth',
1060 | name: 'Forum Popout - Default Width (px)',
1061 | note: 'The width of the forum popout when not actively resized',
1062 | get value() { return settings.defaultForumPopoutWidth; },
1063 | },
1064 | {
1065 | type: 'number',
1066 | id: 'defaultActivityPanelWidth',
1067 | name: 'Activity Panel - Default Width (px)',
1068 | note: 'The width of the activity panel when not actively resized',
1069 | get value() { return settings.defaultActivityPanelWidth; },
1070 | },
1071 | ],
1072 | },
1073 | ],
1074 | };
1075 |
1076 | // Define locale labels
1077 | const locale = {
1078 | en: [
1079 | 'Server List',
1080 | 'Channel List',
1081 | 'Members List',
1082 | 'User Profile',
1083 | 'Message Input',
1084 | 'Window Bar',
1085 | 'Call Window',
1086 | 'User Area',
1087 | 'Search Panel',
1088 | 'Forum Popout',
1089 | 'Activity Panel',
1090 | ],
1091 | get current() { return this[document.documentElement.getAttribute('lang')] ?? this.en; },
1092 | };
1093 |
1094 | // Define icon paths
1095 | const icons = [
1096 | '