DeepL UI Cleaner

Streamlines DeepL's interface for translation-focused use by removing footers, cookie banners, and adding toggle buttons for sidebar and header

当前为 2024-08-16 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name DeepL UI Cleaner
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.4
  5. // @description Streamlines DeepL's interface for translation-focused use by removing footers, cookie banners, and adding toggle buttons for sidebar and header
  6. // @match https://www.deepl.com/*
  7. // @license Unlicense
  8. // @grant none
  9. // @run-at document-start
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. "use strict";
  14.  
  15. // Define selectors for target elements
  16. const TARGETS = {
  17. remove: {
  18. footer: [
  19. "footer",
  20. ".relative.bg-neutral-next-50 > .mobile\\:hidden",
  21. '.bg-white[class*="px-0"][class*="xl:px-"][class*="md:px-"][class*="min-"][class*="px-"]',
  22. ],
  23. cookieBanner: ['[id*="cookieBanner"]', '[class*="cookieBanner"]'],
  24. writePageElements: [
  25. '.bg-white.px-0[class*="xl:px-"][class*="px"][class*="md:px-"][class*="px"][class*="min-"][class*="px"][class*="px"]',
  26. '.mobile\\:hidden.p-8.px-0[class*="xl:px-"][class*="px"][class*="md:px-"][class*="px"][class*="min-"][class*="px"][class*="px"]',
  27. ],
  28. },
  29. toggle: {
  30. leftSidebar:
  31. '[class*="md:block"].bg-white.border-e[class*="w-["][class*="px]"].h-full.hidden[class*="start-0"].border-neutral-next-100',
  32. topHeader: '[class*="BasePageHeader-module--container"]',
  33. },
  34. };
  35.  
  36. // CSS styles for toggle buttons
  37. const BUTTON_STYLES = `
  38. .toggle-button {
  39. position: fixed;
  40. z-index: 10000;
  41. width: 2em;
  42. height: 2em;
  43. background-color: rgba(240, 240, 240, 0.7);
  44. border: 1px solid #ccc;
  45. border-radius: 50%;
  46. cursor: pointer;
  47. display: flex;
  48. align-items: center;
  49. justify-content: center;
  50. font-size: 16px;
  51. transition: all 0.3s;
  52. }
  53. .toggle-button:hover {
  54. background-color: rgba(220, 220, 220, 0.9);
  55. }
  56. `;
  57.  
  58. // Function to inject CSS styles into the page
  59. function injectStyles() {
  60. const style = document.createElement("style");
  61. const hideSelectors = [
  62. ...Object.values(TARGETS.remove).flat(),
  63. ...Object.values(TARGETS.toggle),
  64. ].join(", ");
  65. style.textContent = `
  66. ${hideSelectors} { display: none !important; }
  67. ${BUTTON_STYLES}
  68. `;
  69. (document.head || document.documentElement).appendChild(style);
  70. }
  71.  
  72. // Function to remove unwanted elements from the page
  73. function removeElements() {
  74. Object.values(TARGETS.remove)
  75. .flat()
  76. .forEach((selector) => {
  77. document
  78. .querySelectorAll(selector)
  79. .forEach((element) => element.remove());
  80. });
  81. }
  82.  
  83. // Function to create a toggle button
  84. function createToggleButton(
  85. showIcon,
  86. hideIcon,
  87. onClick,
  88. position,
  89. ariaLabel
  90. ) {
  91. const button = document.createElement("button");
  92. button.className = "toggle-button";
  93. button.textContent = showIcon;
  94. button.setAttribute("aria-label", ariaLabel); // Accessibility improvement
  95. button.addEventListener("click", onClick);
  96. Object.assign(button.style, position);
  97. return button;
  98. }
  99.  
  100. // Function to adjust button positions based on header visibility
  101. function adjustButtonPositions() {
  102. const header = document.querySelector(TARGETS.toggle.topHeader);
  103. const topPosition =
  104. header && getComputedStyle(header).display !== "none"
  105. ? `${header.offsetHeight}px`
  106. : "0.5em";
  107. document.querySelectorAll(".toggle-button").forEach((button) => {
  108. button.style.top = topPosition;
  109. });
  110. }
  111.  
  112. // Function to toggle visibility of elements
  113. function toggleElementVisibility(selector, button, showIcon, hideIcon) {
  114. const elements = document.querySelectorAll(selector);
  115. const isVisible = [...elements].some(
  116. (el) => getComputedStyle(el).display !== "none"
  117. );
  118. elements.forEach((el) =>
  119. el.style.setProperty("display", isVisible ? "none" : "block", "important")
  120. );
  121. button.textContent = isVisible ? showIcon : hideIcon;
  122. adjustButtonPositions();
  123. }
  124.  
  125. // Function to initialize the script
  126. function init() {
  127. try {
  128. removeElements();
  129.  
  130. const buttons = [
  131. {
  132. selector: TARGETS.toggle.leftSidebar,
  133. icons: ["≡", "×"],
  134. position: { left: "0.5em" },
  135. ariaLabel: "Toggle sidebar visibility",
  136. },
  137. {
  138. selector: TARGETS.toggle.topHeader,
  139. icons: ["▼", "▲"],
  140. position: { left: "3em" },
  141. ariaLabel: "Toggle header visibility",
  142. },
  143. ];
  144.  
  145. buttons.forEach(
  146. ({ selector, icons: [showIcon, hideIcon], position, ariaLabel }) => {
  147. const button = createToggleButton(
  148. showIcon,
  149. hideIcon,
  150. () => toggleElementVisibility(selector, button, showIcon, hideIcon),
  151. position,
  152. ariaLabel
  153. );
  154. document.body.appendChild(button);
  155. }
  156. );
  157.  
  158. adjustButtonPositions();
  159.  
  160. // Set up MutationObserver to handle dynamically added elements
  161. const observer = new MutationObserver(() => {
  162. removeElements();
  163. adjustButtonPositions();
  164. });
  165. observer.observe(document.body, { childList: true, subtree: true });
  166. } catch (error) {
  167. console.error("DeepL UI Cleaner encountered an error:", error);
  168. }
  169. }
  170.  
  171. // Inject styles immediately
  172. injectStyles();
  173.  
  174. // Run initialization when DOM is ready
  175. if (document.readyState === "loading") {
  176. document.addEventListener("DOMContentLoaded", init);
  177. } else {
  178. init();
  179. }
  180. })();