Style Fixes for AtCoder

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

Stan na 27-07-2024. Zobacz najnowsza wersja.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

  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. })();