Greasy Fork is available in English.

Style Fixes for AtCoder

Forced attempt to fix style issues on the AtCoder web pages.

Fra 27.07.2024. Se den seneste versjonen.

  1. // ==UserScript==
  2. // @name Style Fixes for AtCoder
  3. // @name:ja Style Fixes for AtCoder
  4. // @namespace https://github.com/roumcha/browser-extensions/tree/main/src/style-fixes-for-atcoder
  5. // @version 2024.7.27
  6. // @description Forced attempt to fix style issues on the AtCoder web pages.
  7. // @description:ja AtCoderのウェブサイトの表示崩れを無理やり抑え込む
  8. // @author Roumcha
  9. // @license Creative Commons Zero v1.0 Universal
  10. // @match https://atcoder.jp/*
  11. // @match https://*.atcoder.jp/*
  12. // @grant GM.xmlHttpRequest
  13. // @connect img.atcoder.jp
  14. // @run-at document-start
  15. // ==/UserScript==
  16.  
  17. "use strict";
  18. (() => {
  19. // src/style-fixes-for-atcoder/infonav.ts
  20. function fix() {
  21. document.addEventListener("DOMContentLoaded", () => {
  22. if (navigator.userAgent.toLowerCase().includes("mobile")) return;
  23. const navElement = document.querySelector("#top-editarea header nav");
  24. const logoDiv = navElement.children[0];
  25. const hamburgerDiv = navElement.children[1];
  26. const menuDiv = navElement.children[2];
  27. hamburgerDiv.remove();
  28. menuDiv.className = "flex gap-x-12";
  29. });
  30. }
  31.  
  32. // src/style-fixes-for-atcoder/mediaquery768.ts
  33. function fix2(fetchFunc) {
  34. mitigateLayoutShift();
  35. window.addEventListener("load", () => {
  36. overwriteStyleElements();
  37. overrideLinkElements(fetchFunc);
  38. });
  39. }
  40. function mitigateLayoutShift() {
  41. const styleElement = document.createElement("style");
  42. styleElement.textContent = `
  43. @media screen and (767.0px < width < 768.0px){
  44. .header-logo > img {
  45. max-width: 40px !important;
  46. }
  47. .keyvisual-logo > img {
  48. max-width: 67px !important;
  49. }
  50. }
  51. `;
  52. document.head.insertAdjacentElement("afterbegin", styleElement);
  53. }
  54. function overwriteStyleElements() {
  55. for (const styleElement of document.head.getElementsByTagName("style")) {
  56. if (styleElement.textContent) {
  57. styleElement.textContent = modifyCss(styleElement.textContent);
  58. }
  59. }
  60. }
  61. function overrideLinkElements(requestFunc) {
  62. for (const linkElement of document.head.getElementsByTagName("link")) {
  63. if (linkElement.rel !== "stylesheet") continue;
  64. if (!linkElement.href.includes("atcoder")) continue;
  65. if (linkElement.href.includes("bootstrap")) continue;
  66. requestFunc(linkElement.href).then((response) => {
  67. const styleElement = document.createElement("style");
  68. styleElement.textContent = modifyCss(response);
  69. linkElement.insertAdjacentElement("afterend", styleElement);
  70. });
  71. }
  72. }
  73. function modifyCss(css) {
  74. return css.replace(/(@media[^{]+[0-9]+[13579])()(px[^{]*{)/g, "$1.95$3");
  75. }
  76.  
  77. // src/style-fixes-for-atcoder/multi-line-nav.ts
  78. function fix3() {
  79. window.addEventListener("DOMContentLoaded", () => {
  80. const styleElement = document.createElement("style");
  81. styleElement.textContent = `
  82. @media screen and (991px < width){
  83. .nav .contest-title {
  84. width: calc((100vw - 80px - 253px) * 0.9);
  85. text-wrap: nowrap;
  86. overflow: hidden;
  87. text-overflow: ellipsis;
  88. }
  89. }
  90. `;
  91. document.head.insertAdjacentElement("afterbegin", styleElement);
  92. });
  93. }
  94.  
  95. // src/style-fixes-for-atcoder/lib.ts
  96. function fixStyle(options) {
  97. if (document.head.classList.contains("style-fixed")) return;
  98. document.head.classList.add("style-fixed");
  99. if (location.href.startsWith("https://atcoder.jp")) {
  100. fix2(options.fetchFunc);
  101. }
  102. if (location.href.startsWith("https://atcoder.jp/contests/")) {
  103. fix3();
  104. }
  105. if (location.href.startsWith("https://info.atcoder.jp")) {
  106. fix();
  107. }
  108. }
  109.  
  110. // src/style-fixes-for-atcoder/user-script.ts
  111. fixStyle({
  112. fetchFunc: (url) => GM.xmlHttpRequest({ method: "GET", url }).then(
  113. (response) => response.responseText
  114. )
  115. });
  116. })();