Spotify Web Sidebar Toggler

Adds the ability to toggle the main sidebar on Spotify Web using a keyboard shortcut (ctrl + alt + B), original code from https://github.com/dumptyd/slack-sidebar-toggler

  1. // ==UserScript==
  2. // @name Spotify Web Sidebar Toggler
  3. // @description Adds the ability to toggle the main sidebar on Spotify Web using a keyboard shortcut (ctrl + alt + B), original code from https://github.com/dumptyd/slack-sidebar-toggler
  4. // @author dearrrfish (http://github.com/dearrrfish)
  5. // @version 1.2.0
  6. // @namespace http://github.com/dearrrfish
  7. // @include https://open.spotify.com/*
  8. // @grant GM_addStyle
  9. // ==/UserScript==
  10.  
  11. (function () {
  12. 'use strict';
  13.  
  14. const combinator = {
  15. on(passedCombination, callback) {
  16. const combination = passedCombination.map(c => c.toLowerCase());
  17. let buffer = [];
  18. let skipNextKeyUp = false;
  19.  
  20. const isCombinationMet = () => buffer.toString() === combination.toString();
  21.  
  22. document.addEventListener('keydown', e => {
  23. const key = e.key.toLowerCase();
  24. buffer.push(key);
  25.  
  26. if (isCombinationMet()) {
  27. buffer.pop();
  28. if (buffer.length) skipNextKeyUp = true;
  29.  
  30. callback();
  31. }
  32. });
  33.  
  34. document.addEventListener('keyup', e => {
  35. if (skipNextKeyUp) {
  36. skipNextKeyUp = false;
  37. return;
  38. }
  39. buffer = [];
  40. });
  41. }
  42. };
  43.  
  44. const onLoad = callback => {
  45. const loadedStates = ['loaded', 'interactive', 'complete'];
  46. if (loadedStates.includes(document.readyState)) {
  47. callback();
  48. }
  49. else {
  50. window.addEventListener('load', () => {
  51. callback();
  52. });
  53. }
  54. };
  55.  
  56. const style = {
  57. leftSidebarCollapsedClassName: 'SST-left-sidebar-collapsed',
  58. containerSelector: '.Root__top-container',
  59. navbarSelector: '.Root__nav-bar',
  60. mainviewSelector: '.Root__main-view',
  61. topbarSelector: '.Root__top-bar header',
  62. nowplayingbarSelector: '.Root__now-playing-bar footer .now-playing-bar',
  63. };
  64. GM_addStyle(`
  65.  
  66. .${style.leftSidebarCollapsedClassName} ${style.topbarSelector} {
  67. max-width: 100vw;
  68. }
  69.  
  70. ${style.containerSelector} {
  71. transition: .2s;
  72. }
  73.  
  74. .${style.leftSidebarCollapsedClassName} ${style.navbarSelector} {
  75. width: 0;
  76. opacity: 0;
  77. transition: width .2s, opacity .2s;
  78. }
  79.  
  80. ${style.mainviewSelector} {
  81. transition: width .2s;
  82. }
  83.  
  84. ${style.mainviewSelector} > div.nav-bar-toggler {
  85. position: absolute;
  86. left: 0;
  87. top: 0;
  88. bottom: 0;
  89. width: 7px;
  90. height: 100%;
  91. display: block;
  92. }
  93. ${style.mainviewSelector} > div.nav-bar-toggler:hover {
  94. cursor: e-resize;
  95. content: linear-gradient(#e66465, #9198e5);
  96. }
  97. `);
  98.  
  99. GM_addStyle(`
  100. body {
  101. font-family: Microsoft Yahei;
  102. }
  103.  
  104. @media screen and (max-width: 700px) {
  105. body {
  106. min-width: unset;
  107. }
  108.  
  109. ${style.nowplayingbarSelector} {
  110. width: 100%;
  111. min-width: unset;
  112. max-width: 100vw;
  113. min-height: 70px;
  114. padding: 10px 20px;
  115. height: unset;
  116. display: flex;
  117. flex-direction: row;
  118. flex-wrap: wrap;
  119. }
  120.  
  121. ${style.nowplayingbarSelector} .now-playing-bar__left {
  122. width: auto;
  123. order: 1;
  124. }
  125.  
  126. ${style.nowplayingbarSelector} .now-playing-bar__center {
  127. width: 100%;
  128. order: 3;
  129. }
  130.  
  131. ${style.nowplayingbarSelector} .now-playing-bar__right {
  132. max-width: 25%;
  133. min-width: unset;
  134. order: 2;
  135. }
  136.  
  137. ${style.nowplayingbarSelector} .now-playing-bar__right__inner {
  138. width: 100%;
  139. }
  140. }
  141. `)
  142.  
  143.  
  144. function toggleSideBar() {
  145. document.body.classList.toggle(style.leftSidebarCollapsedClassName);
  146. }
  147.  
  148. onLoad(() => {
  149. combinator.on(['Control', 'Alt', 'B'], () => {
  150. toggleSideBar();
  151. });
  152.  
  153. const checkMainViewExist = setInterval(() => {
  154. const mainview = document.querySelector(style.mainviewSelector);
  155. if (mainview) {
  156. const toggler = document.createElement('div');
  157. toggler.classList.add('nav-bar-toggler')
  158. toggler.onmousedown = (evt) => {
  159. evt.preventDefault();
  160. toggleSideBar();
  161. }
  162. mainview.appendChild(toggler);
  163. clearInterval(checkMainViewExist);
  164. }
  165. }, 500)
  166.  
  167. });
  168. })();