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-10-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name DeepL UI Cleaner
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.6
  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. // @include https://www.deepl.com/*
  8. // @license Unlicense
  9. // @grant none
  10. // @run-at document-idle
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. "use strict";
  15.  
  16. // Define selectors for target elements
  17. const TARGETS = {
  18. remove: {
  19. footer: [
  20. "footer",
  21. ".relative.bg-neutral-next-50 > .mobile\\:hidden",
  22. '.bg-white[class*="px-0"][class*="xl:px-"][class*="md:px-"][class*="min-"][class*="px"]',
  23. ],
  24. cookieBanner: ['[id*="cookieBanner"]', '[class*="cookieBanner"]'],
  25. writePageElements: [
  26. '.bg-white.px-0[class*="xl:px-"][class*="px"][class*="md:px-"][class*="px"][class*="min-"][class*="px"][class*="px"]',
  27. '.mobile\\:hidden.p-8.px-0[class*="xl:px-"][class*="px"][class*="md:px-"][class*="px"][class*="min-"][class*="px"][class*="px"]',
  28. '.bg-white.min-\\[1280px\\]\\:px-\\[70px\\]'
  29. ],
  30. },
  31. toggle: {
  32. topHeader: 'header'
  33. },
  34. };
  35.  
  36. // CSS styles for toggle buttons and initial header state
  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. ${TARGETS.toggle.topHeader} {
  57. display: none !important;
  58. }
  59. `;
  60.  
  61. // Function to inject CSS styles into the page
  62. function injectStyles() {
  63. const style = document.createElement("style");
  64. const hideSelectors = [
  65. ...Object.values(TARGETS.remove).flat(),
  66. ].join(", ");
  67. style.textContent = `
  68. ${hideSelectors} { display: none !important; }
  69. ${BUTTON_STYLES}
  70. `;
  71. (document.head || document.documentElement).appendChild(style);
  72. }
  73.  
  74. // Function to remove unwanted elements from the page
  75. function removeElements() {
  76. Object.values(TARGETS.remove)
  77. .flat()
  78. .forEach((selector) => {
  79. document
  80. .querySelectorAll(selector)
  81. .forEach((element) => element.remove());
  82. });
  83. }
  84.  
  85. // Function to create a toggle button
  86. function createToggleButton(
  87. showIcon,
  88. hideIcon,
  89. onClick,
  90. position,
  91. ariaLabel
  92. ) {
  93. const button = document.createElement("button");
  94. button.className = "toggle-button";
  95. button.textContent = showIcon; // Starting with show icon since header is hidden
  96. button.setAttribute("aria-label", ariaLabel);
  97. button.addEventListener("click", onClick);
  98. Object.assign(button.style, position);
  99. return button;
  100. }
  101.  
  102. // Function to adjust button positions based on header visibility
  103. function adjustButtonPositions() {
  104. const header = document.querySelector(TARGETS.toggle.topHeader);
  105. const topPosition =
  106. header && getComputedStyle(header).display !== "none"
  107. ? `${header.offsetHeight}px`
  108. : "0.5em";
  109. document.querySelectorAll(".toggle-button").forEach((button) => {
  110. button.style.top = topPosition;
  111. });
  112. }
  113.  
  114. // Function to toggle visibility of elements
  115. function toggleElementVisibility(selector, button, showIcon, hideIcon) {
  116. const elements = document.querySelectorAll(selector);
  117. const isVisible = [...elements].some(
  118. (el) => getComputedStyle(el).display !== "none"
  119. );
  120. elements.forEach((el) =>
  121. el.style.setProperty("display", isVisible ? "none" : "block", "important")
  122. );
  123. button.textContent = isVisible ? showIcon : hideIcon;
  124. adjustButtonPositions();
  125. }
  126.  
  127. // Function to initialize the script
  128. function init() {
  129. try {
  130. removeElements();
  131.  
  132. const buttons = [
  133. {
  134. selector: TARGETS.toggle.topHeader,
  135. icons: ["▼", "▲"],
  136. position: { left: "0.5em" },
  137. ariaLabel: "Toggle header visibility",
  138. },
  139. ];
  140.  
  141. buttons.forEach(
  142. ({ selector, icons: [showIcon, hideIcon], position, ariaLabel }) => {
  143. const button = createToggleButton(
  144. showIcon,
  145. hideIcon,
  146. () => toggleElementVisibility(selector, button, showIcon, hideIcon),
  147. position,
  148. ariaLabel
  149. );
  150. document.body.appendChild(button);
  151. }
  152. );
  153.  
  154. adjustButtonPositions();
  155.  
  156. // Set up MutationObserver to handle dynamically added elements
  157. const observer = new MutationObserver(() => {
  158. removeElements();
  159. adjustButtonPositions();
  160. });
  161. observer.observe(document.body, { childList: true, subtree: true, attributes: true });
  162. } catch (error) {
  163. console.error("DeepL UI Cleaner encountered an error:", error);
  164. }
  165. }
  166.  
  167. // Inject styles immediately
  168. injectStyles();
  169.  
  170. // Run initialization when DOM is ready
  171. if (document.readyState === "loading") {
  172. document.addEventListener("DOMContentLoaded", init);
  173. } else {
  174. init();
  175. }
  176. })();