Style Fixes for AtCoder

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

As of 08.03.2024. See ბოლო ვერსია.

  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 2023.12.1
  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"))
  23. return;
  24. const navElement = document.querySelector("#top-editarea header nav");
  25. const logoDiv = navElement.children[0];
  26. const hamburgerDiv = navElement.children[1];
  27. const menuDiv = navElement.children[2];
  28. hamburgerDiv.remove();
  29. menuDiv.className = "flex gap-x-12";
  30. });
  31. }
  32.  
  33. // src/style-fixes-for-atcoder/mediaquery768.ts
  34. function fix2(fetchFunc) {
  35. mitigateLayoutShift();
  36. window.addEventListener("load", () => {
  37. overwriteStyleElements();
  38. overrideLinkElements(fetchFunc);
  39. });
  40. }
  41. function mitigateLayoutShift() {
  42. const styleElement = document.createElement("style");
  43. styleElement.textContent = `
  44. @media screen and (767.0px < width < 768.0px){
  45. .header-logo > img {
  46. max-width: 40px !important;
  47. }
  48. .keyvisual-logo > img {
  49. max-width: 67px !important;
  50. }
  51. }
  52. `;
  53. document.head.insertAdjacentElement("afterbegin", styleElement);
  54. }
  55. function overwriteStyleElements() {
  56. for (const styleElement of document.head.getElementsByTagName("style")) {
  57. if (styleElement.textContent) {
  58. styleElement.textContent = modifyCss(styleElement.textContent);
  59. }
  60. }
  61. }
  62. function overrideLinkElements(requestFunc) {
  63. for (const linkElement of document.head.getElementsByTagName("link")) {
  64. if (linkElement.rel !== "stylesheet")
  65. continue;
  66. if (!linkElement.href.includes("atcoder"))
  67. continue;
  68. if (linkElement.href.includes("bootstrap"))
  69. continue;
  70. requestFunc(linkElement.href).then((response) => {
  71. const styleElement = document.createElement("style");
  72. styleElement.textContent = modifyCss(response);
  73. linkElement.insertAdjacentElement("afterend", styleElement);
  74. });
  75. }
  76. }
  77. function modifyCss(css) {
  78. return css.replace(/(@media[^{]+[0-9]+[13579])()(px[^{]*{)/g, "$1.95$3");
  79. }
  80.  
  81. // src/style-fixes-for-atcoder/lib.ts
  82. function fixStyle(options) {
  83. if (document.head.classList.contains("style-fixed"))
  84. return;
  85. document.head.classList.add("style-fixed");
  86. if (location.href.startsWith("https://atcoder.jp")) {
  87. fix2(options.fetchFunc);
  88. }
  89. if (location.href.startsWith("https://info.atcoder.jp")) {
  90. fix();
  91. }
  92. }
  93.  
  94. // src/style-fixes-for-atcoder/user-script.ts
  95. fixStyle({
  96. fetchFunc: (url) => GM.xmlHttpRequest({ method: "GET", url }).then(
  97. (response) => response.responseText
  98. )
  99. });
  100. })();